Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>Vars.add(scope.getVar(root.getString()));
}
}
/**
* Whether the given variable is forbidden from being inlined.
*/
private boolean isVarInlineForbidden(Var var) {
// A variable may not be inlined if:
// 1) The variable is exported,
// 2) A reference to the variable has been inlined. We're downstream
// of the mechanism that creates variable references, so we don't
// have a good way to update the reference. Just punt on it.
// 3) Don't inline the special RENAME_PROPERTY_FUNCTION_NAME
return compiler.getCodingConvention().isExported(var.name)
|| RenameProperties.RENAME_PROPERTY_FUNCTION_NAME.equals(var.name)
|| staleVars.contains(var);
}
/**
* Do the actual work of inlining a single declaration into a single
* reference.
*/
private void inline(Var v, Reference declaration,
Reference init, Reference reference) {
Node value = init.getAssignedValue();
Preconditions.checkState(value != null);
// Check for function declarations before the value is moved in the AST.
boolean isFunctionDeclaration = NodeUtil.isFunctionDeclaration(value);
inlineValue(v, reference, value.detachFromParent());
if (declaration != init) {
Node expressRoot = init.getGrandparent();
Preconditions.checkState(expressRoot.getType() == Token.EXPR_RESULT);
NodeUtil.removeChild(expressRoot.getParent(), expressRoot);
}
// Function declarations have already been removed.
if (!isFunctionDeclaration) {
removeDeclaration(declaration);
} else {
compiler.reportCodeChange();
}
}
/**
* Inline an immutable variable into all of its references.
*/
private void inlineWellDefinedVariable(Var v, Node value,
List<Reference> refSet) {
Reference decl = refSet.get(0);
for (int i = 1; i < refSet.size(); i++) {
inlineValue(v, refSet.get(i), value.cloneTree());
}
removeDeclaration(decl);
}
/**
* Inline a declared constant.
*/
private void inlineDeclaredConstant(Var v, Node value,
List<Reference> refSet) {
//
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> return false;
}
// Is the constant's value immutable?
if (!NodeUtil.isImmutableValue(value)) {
return false;
}
// Determine if we should really inline a String or not.
return value.getType() != Token.STRING ||
isStringWorthInlining(var, refInfo.references);
}
/**
* Compute whether the given string is worth inlining.
*/
private boolean isStringWorthInlining(Var var, List<Reference> refs) {
if (!inlineAllStrings && !var.isDefine()) {
int len = var.getInitialValue().getString().length() + "''".length();
// if not inlined: var xx="value"; .. xx .. xx ..
// The 4 bytes per reference is just a heuristic:
// 2 bytes per var name plus maybe 2 bytes if we don't inline, e.g.
// in the case of "foo " + CONST + " bar"
int noInlineBytes = "var xx=;".length() + len +
4 * (refs.size() - 1);
// if inlined:
// I'm going to assume that half of the quotes will be eliminated
// thanks to constant folding, therefore I subtract 1 (2/2=1) from
// the string length.
int inlineBytes = (len - 1) * (refs.size() - 1);
// Not inlining if doing so uses more bytes, or this constant is being
// defined.
return noInlineBytes >= inlineBytes;
}
return true;
}
/**
* @return true if the provided reference and declaration can be safely
* inlined according to our criteria
*/
private boolean canInline(
Reference declaration,
Reference initialization,
Reference reference) {
if (!isValidDeclaration(declaration)
|| !isValidInitialization(initialization)
|| !isValidReference(reference)) {
return false;
}
// If the value is read more than once, skip it.
// VAR declarations and EXPR_RESULT don't need the value, but other
// ASSIGN expressions parents do.
if (declaration != initialization &&
initialization.getGrandparent().getType() != Token.EXPR_RESULT) {
return false;
}
// Be very conservative and do no cross control structures or
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> case Token.SHEQ:
case Token.SHNE:
case Token.CASE:
Node left;
Node right;
if (operatorToken == Token.CASE) {
left = condition.getParent().getFirstChild(); // the switch condition
right = condition.getFirstChild();
} else {
left = condition.getFirstChild();
right = condition.getLastChild();
}
Node typeOfNode = null;
Node stringNode = null;
if (left.getType() == Token.TYPEOF && right.getType() == Token.STRING) {
typeOfNode = left;
stringNode = right;
} else if (right.getType() == Token.TYPEOF &&
left.getType() == Token.STRING) {
typeOfNode = right;
stringNode = left;
}
if (typeOfNode != null && stringNode != null) {
Node operandNode = typeOfNode.getFirstChild();
JSType operandType = getTypeIfRefinable(operandNode, blindScope);
if (operandType != null) {
boolean resultEqualsValue = operatorToken == Token.EQ ||
operatorToken == Token.SHEQ || operatorToken == Token.CASE;
if (!outcome) {
resultEqualsValue = !resultEqualsValue;
}
return caseTypeOf(operandNode, operandType, stringNode.getString(),
resultEqualsValue, blindScope);
}
}
}
switch (operatorToken) {
case Token.AND:
if (outcome) {
return caseAndOrNotShortCircuiting(condition.getFirstChild(),
condition.getLastChild(), blindScope, true);
} else {
return caseAndOrMaybeShortCircuiting(condition.getFirstChild(),
condition.getLastChild(), blindScope, true);
}
case Token.OR:
if (!outcome) {
return caseAndOrNotShortCircuiting(condition.getFirstChild(),
condition.getLastChild(), blindScope, false);
} else {
return caseAndOrMaybeShortCircuiting(condition.getFirstChild(),
condition.getLastChild(), blindScope, false);
}
case Token.EQ:
if (outcome) {
return caseEquality(condition, blindScope, EQ);
} else {
return caseEquality(condition, blindScope, NE);
}
case Token.NE:
if (outcome) {
return caseEquality(condition
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>, blindScope, NE);
} else {
return caseEquality(condition, blindScope, EQ);
}
case Token.SHEQ:
if (outcome) {
return caseEquality(condition, blindScope, SHEQ);
} else {
return caseEquality(condition, blindScope, SHNE);
}
case Token.SHNE:
if (outcome) {
return caseEquality(condition, blindScope, SHNE);
} else {
return caseEquality(condition, blindScope, SHEQ);
}
case Token.NAME:
case Token.GETPROP:
return caseNameOrGetProp(condition, blindScope, outcome);
case Token.ASSIGN:
return firstPreciserScopeKnowingConditionOutcome(
condition.getFirstChild(),
firstPreciserScopeKnowingConditionOutcome(
condition.getFirstChild().getNext(), blindScope, outcome),
outcome);
case Token.NOT:
return firstPreciserScopeKnowingConditionOutcome(
condition.getFirstChild(), blindScope, !outcome);
case Token.LE:
case Token.LT:
case Token.GE:
case Token.GT:
if (outcome) {
return caseEquality(condition, blindScope, INEQ);
}
break;
case Token.INSTANCEOF:
return caseInstanceOf(
condition.getFirstChild(), condition.getLastChild(), blindScope,
outcome);
case Token.IN:
if (outcome && condition.getFirstChild().getType() == Token.STRING) {
return caseIn(condition.getLastChild(),
condition.getFirstChild().getString(), blindScope);
}
break;
case Token.CASE:
Node left =
condition.getParent().getFirstChild(); // the switch condition
Node right = condition.getFirstChild();
if (outcome) {
return caseEquality(left, right, blindScope, SHEQ);
} else {
return caseEquality(left, right, blindScope, SHNE);
}
}
return nextPreciserScopeKnowingConditionOutcome(
condition, blindScope, outcome);
}
private FlowScope caseEquality(Node condition, FlowScope blindScope,
Function<TypePair, TypePair> merging) {
return caseEquality(condition.getFirstChild(), condition.getLastChild(),
blindScope, merging);
}
private FlowScope caseEquality(Node
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> 1;
String name = node.getFirstChild().getString();
// Store the context for this label name.
LabelInfo li = new LabelInfo(currentDepth);
Preconditions.checkState(!current.renameMap.containsKey(name));
current.renameMap.put(name, li);
// Create a new name, if needed, for this depth.
if (names.size() < currentDepth) {
names.add(nameGenerator.generateNextName());
}
String newName = getNameForId(currentDepth);
compiler.addToDebugLog("label renamed: " + name + " => " + newName);
}
return true;
}
/**
* Delegate the actual processing of the node to visitLabel and
* visitBreakOrContinue.
*
* {@inheritDoc}
*/
public void visit(NodeTraversal nodeTraversal, Node node, Node parent) {
switch (node.getType()) {
case Token.LABEL:
visitLabel(node, parent);
break;
case Token.BREAK:
case Token.CONTINUE:
visitBreakOrContinue(node);
break;
}
}
/**
* Rename label references in breaks and continues.
* @param node The break or continue node.
*/
private void visitBreakOrContinue(Node node) {
Node nameNode = node.getFirstChild();
if (nameNode != null) {
// This is a named break or continue;
String name = nameNode.getString();
Preconditions.checkState(name.length() != 0);
LabelInfo li = getLabelInfo(name);
if (li != null) {
String newName = getNameForId(li.id);
// Mark the label as referenced so it isn't removed.
li.referenced = true;
if (!name.equals(newName)) {
// Give it the short name.
nameNode.setString(newName);
compiler.reportCodeChange();
}
}
}
}
/**
* Rename or remove labels.
* @param node The label node.
* @param parent The parent of the label node.
*/
private void visitLabel(Node node, Node parent) {
Node nameNode = node.getFirstChild();
Preconditions.checkState(nameNode != null);
String name = nameNode.getString();
LabelInfo li = getLabelInfo
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> == Token.COMMA) {
Node gramps = parent.getParent();
if (gramps.getType() == Token.CALL &&
parent == gramps.getFirstChild()) {
// Semantically, a direct call to eval is different from an indirect
// call to an eval. See Ecma-262 S15.1.2.1. So it's ok for the first
// expression to a comma to be a no-op if it's used to indirect
// an eval.
if (n == parent.getFirstChild() &&
parent.getChildCount() == 2 &&
n.getNext().getType() == Token.NAME &&
"eval".equals(n.getNext().getString())) {
return;
}
}
if (n == parent.getLastChild()) {
for (Node an : parent.getAncestors()) {
int ancestorType = an.getType();
if (ancestorType == Token.COMMA)
continue;
if (ancestorType != Token.EXPR_RESULT &&
ancestorType != Token.BLOCK)
return;
else
break;
}
}
} else if (pt != Token.EXPR_RESULT && pt != Token.BLOCK) {
if (pt == Token.FOR && parent.getChildCount() == 4 &&
(n == parent.getFirstChild() ||
n == parent.getFirstChild().getNext().getNext())) {
// Fall through and look for warnings for the 1st and 3rd child
// of a for.
} else {
return; // it might be ok to not have a side-effect
}
}
if (NodeUtil.isSimpleOperatorType(n.getType()) ||
!NodeUtil.mayHaveSideEffects(n, t.getCompiler())) {
if (n.isQualifiedName() && n.getJSDocInfo() != null) {
// This no-op statement was there so that JSDoc information could
// be attached to the name. This check should not complain about it.
return;
} else if (NodeUtil.isExpressionNode(n)) {
// we already reported the problem when we visited the child.
return;
}
String msg = "This code lacks side-effects. Is there a bug?";
if (n.getType() == Token.STRING) {
msg =
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> return false;
}
// In compiled code, '$' is often a namespace delimiter. To allow inlining
// of namespaced constants, we strip off any namespaces here.
int pos = name.lastIndexOf('$');
if (pos >= 0) {
name = name.substring(pos + 1);
if (name.length() == 0) {
return false;
}
}
return isConstantKey(name);
}
@Override
public boolean isConstantKey(String name) {
if (name.isEmpty() || !Character.isUpperCase(name.charAt(0))) {
return false;
}
// hack way of checking that there aren't any lower-case letters
return name.toUpperCase().equals(name);
}
/**
* {@inheritDoc}
*
* <p>This enforces Google's convention about enum key names. They must match
* the regular expression {@code [A-Z0-9][A-Z0-9_]*}.
*
* <p>Examples:
* <ul>
* <li>A</li>
* <li>213</li>
* <li>FOO_BAR</li>
* </ul>
*/
@Override
public boolean isValidEnumKey(String key) {
return ENUM_KEY_PATTERN.matcher(key).matches();
}
/**
* {@inheritDoc}
*
* <p>In Google code, parameter names beginning with {@code opt_} are
* treated as optional arguments.
*/
@Override
public boolean isOptionalParameter(Node parameter) {
return parameter.getString().startsWith(OPTIONAL_ARG_PREFIX);
}
@Override
public boolean isVarArgsParameter(Node parameter) {
return VAR_ARGS_NAME.equals(parameter.getString());
}
/**
* {@inheritDoc}
*
* <p>In Google code, any global name starting with an underscore is
* considered exported.
*/
@Override
public boolean isExported(String name, boolean local) {
return !local && name.startsWith("_");
}
/**
* {@inheritDoc}
*
* <p>In Google code, private names end with an underscore, and exported
* names are never considered private (see {@link #isExported}).
*/
@Override
public boolean is
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>/*
* Copyright 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp.parsing;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.javascript.jscomp.mozilla.rhino.CompilerEnvirons;
import com.google.javascript.jscomp.mozilla.rhino.Context;
import com.google.javascript.jscomp.mozilla.rhino.ErrorReporter;
import com.google.javascript.jscomp.mozilla.rhino.EvaluatorException;
import com.google.javascript.jscomp.mozilla.rhino.Parser;
import com.google.javascript.jscomp.mozilla.rhino.ast.AstRoot;
import com.google.javascript.rhino.Node;
import java.io.IOException;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.logging.Logger;
public class ParserRunner {
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
private static Set<String> annotationNames = null;
private static Set<String> suppressionNames = null;
// Should never need to instantiate class of static methods.
private ParserRunner() {}
public static Config createConfig(boolean isIdeMode) {
initResourceConfig();
return new Config(annotationNames, suppressionNames, isIdeMode);
}
private static synchronized void initResourceConfig() {
if (annotationNames != null) {
return;
}
ResourceBundle config = ResourceBundle.getBundle(configResource);
annotationNames = extractList(config.getString("jsdoc.annotations
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>"));
suppressionNames = extractList(config.getString("jsdoc.suppressions"));
}
private static Set<String> extractList(String configProp) {
String[] names = configProp.split(",");
Set<String> trimmedNames = Sets.newHashSet();
for (String name : names) {
trimmedNames.add(name.trim());
}
return ImmutableSet.copyOf(trimmedNames);
}
/**
* Parses the JavaScript text given by a reader.
*
* @param sourceName The filename.
* @param sourceString Source code from the file.
* @param errorReporter An error.
* @param logger A logger.
* @return The AST of the given text.
* @throws IOException
*/
public static Node parse(String sourceName,
String sourceString,
Config config,
ErrorReporter errorReporter,
Logger logger) throws IOException {
Context cx = Context.enter();
cx.setErrorReporter(errorReporter);
cx.setLanguageVersion(Context.VERSION_1_5);
CompilerEnvirons compilerEnv = new CompilerEnvirons();
compilerEnv.initFromContext(cx);
compilerEnv.setRecordingComments(true);
compilerEnv.setRecordingLocalJsDocComments(true);
compilerEnv.setWarnTrailingComma(true);
if (config.isIdeMode) {
compilerEnv.setReservedKeywordAsIdentifier(true);
compilerEnv.setAllowMemberExprAsFunctionName(true);
}
Parser p = new Parser(compilerEnv, errorReporter);
AstRoot astRoot = null;
try {
astRoot = p.parse(sourceString, sourceName, 1);
} catch (EvaluatorException e) {
logger.info("Error parsing " + sourceName + ": " + e.getMessage());
} finally {
Context.exit();
}
Node root = null;
if (astRoot != null) {
root = IRFactory.transformTree(
astRoot, sourceString, config, errorReporter);
root.setIsSyntheticBlock(true);
}
return root;
}
}
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> this.callback = callback;
}
public void visit(NodeTraversal t, Node n, Node parent) {
switch (n.getType()) {
// Function calls
case Token.CALL:
Node child = n.getFirstChild();
String name = null;
// NOTE: The normalization pass insures that local names do not
// collide with global names.
if (child.getType() == Token.NAME) {
name = child.getString();
} else if (child.getType() == Token.FUNCTION) {
name = anonFunctionMap.get(child);
} else if (NodeUtil.isFunctionObjectCall(n)) {
Preconditions.checkState(NodeUtil.isGet(child));
Node fnIdentifingNode = child.getFirstChild();
if (fnIdentifingNode.getType() == Token.NAME) {
name = fnIdentifingNode.getString();
} else if (fnIdentifingNode.getType() == Token.FUNCTION) {
name = anonFunctionMap.get(fnIdentifingNode);
}
}
if (name != null) {
FunctionState fs = functionMap.get(name);
// Only visit call-sites for functions that can be inlined.
if (fs != null) {
callback.visitCallSite(t, n, parent, fs);
}
}
break;
}
}
}
/**
* Find references to functions that are inlinable.
*/
private class FindCandidatesReferences
extends CallVisitor
implements CallVisitorCallback {
FindCandidatesReferences(
Map<String, FunctionState> fns,
Map<Node, String> anonFns) {
super(fns, anonFns, null);
this.callback = this;
}
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
super.visit(t, n, parent);
if (n.getType() == Token.NAME) {
checkNameUsage(t, n, parent);
}
}
public void visitCallSite(
NodeTraversal t, Node callNode, Node parent, FunctionState fs) {
maybeAddReference(t, fs, callNode, t.getModule());
}
void maybeAddReference(NodeTraversal t, FunctionState fs,
Node callNode, JSModule module)
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>parent.getType() == Token.CALL && parent.getFirstChild() == n) {
// This is a normal reference to the function.
return;
}
// Check for a ".call" to the named function:
// CALL
// GETPROP/GETELEM
// NAME
// STRING == "call"
// This-Value
// Function-parameter-1
// ...
if (NodeUtil.isGet(parent)
&& n == parent.getFirstChild()
&& n.getNext().getType() == Token.STRING
&& n.getNext().getString().equals("call")) {
Node gramps = n.getAncestor(2);
if (gramps.getType() == Token.CALL
&& gramps.getFirstChild() == parent) {
// Yep, a ".call".
return;
}
}
// Other refs to a function name remove its candidacy for inlining
String name = n.getString();
FunctionState fs = fns.get(name);
if (fs == null) {
return;
}
// If the name is being assigned to it can not be inlined.
if (parent.getType() == Token.ASSIGN && parent.getFirstChild() == n) {
// e.g. bar = something; <== we can't inline "bar"
// so mark the function as uninlinable.
// TODO(johnlenz): Should we just remove it from fns here?
fs.setInline(false);
} else {
// e.g. var fn = bar; <== we can't inline "bar"
// As this reference can't be inlined mark the function as
// unremovable.
fs.setRemove(false);
}
}
}
/**
* Inline functions at the call sites.
*/
private class Inline implements CallVisitorCallback {
private final FunctionInjector injector;
Inline(FunctionInjector injector) {
this.injector = injector;
}
public void visitCallSite(
NodeTraversal t, Node callNode, Node parent, FunctionState fs) {
Preconditions.checkState(fs.hasExistingFunctionDefinition());
if (fs.canInline()) {
Reference ref = fs.getReference(callNode);
// There are two cases ref can be null: if the call site
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>ConflictsForFunction(fs);
}
}
/**
* @see #resolveInlineConflicts
*/
private void resolveInlineConflictsForFunction(FunctionState fs) {
// Functions that aren't referenced don't cause conflicts.
if (!fs.hasReferences()) {
return;
}
Node fnNode = fs.getFn().getFunctionNode();
Set<String> names = findCalledFunctions(fnNode);
if (!names.isEmpty()) {
// Prevent the removal of the referenced functions.
for (String name : names) {
FunctionState fsCalled = fns.get(name);
if (fsCalled != null && fsCalled.canRemove()) {
fsCalled.setRemove(false);
// For functions that can no longer be removed, check if they should
// still be inlined.
if (!mimimizeCost(fsCalled)) {
// It can't be inlined remove it from the list.
fsCalled.setInline(false);
}
}
}
// Make a copy of the Node, so it isn't changed by other inlines.
fs.setSafeFnNode(fs.getFn().getFunctionNode().cloneTree());
}
}
/**
* This functions that may be called directly.
*/
private Set<String> findCalledFunctions(Node node) {
Set<String> changed = Sets.newHashSet();
findCalledFunctions(node, changed);
return changed;
}
/**
* @see #findCalledFunctions(Node)
*/
private void findCalledFunctions(
Node node, Set<String> changed) {
Preconditions.checkArgument(changed != null);
// For each referenced function, add a new reference
if (node.getType() == Token.CALL) {
Node child = node.getFirstChild();
if (child.getType() == Token.NAME) {
String name = child.getString();
changed.add(name);
}
}
for (Node c = node.getFirstChild(); c != null; c = c.getNext()) {
findCalledFunctions(c, changed);
}
}
/**
* For any call-site that needs it, prepare the call-site for inlining
* by rewriting the containing expression.
*/
private void decomposeExpressions(Set<String> fnNames) {
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>newHashMap();
}
references.put(ref.callNode, ref);
}
public Collection<Reference> getReferences() {
return getReferencesInternal().values();
}
public Reference getReference(Node n) {
return getReferencesInternal().get(n);
}
public Set<String> getNamesToAlias() {
if (namesToAlias == null) {
return Collections.emptySet();
}
return Collections.unmodifiableSet(namesToAlias);
}
public void setNamesToAlias(Set<String> names) {
namesToAlias = names;
}
public void setModule(JSModule module) {
this.module = module;
}
public JSModule getModule() {
return module;
}
}
/**
* Interface for dealing with function declarations and function
* expressions equally
*/
private static interface Function {
/** Gets the name of the function */
public String getName();
/** Gets the function node */
public Node getFunctionNode();
/** Removes itself from the javascript */
public void remove();
public Node getDeclaringBlock();
}
/** NamedFunction implementation of the Function interface */
private static class NamedFunction implements Function {
private final Node fn;
public NamedFunction(Node fn) {
this.fn = fn;
}
public String getName() {
return fn.getFirstChild().getString();
}
public Node getFunctionNode() {
return fn;
}
public void remove() {
NodeUtil.removeChild(fn.getParent(), fn);
}
@Override
public Node getDeclaringBlock() {
return fn.getParent();
}
}
/** FunctionVar implementation of the Function interface */
private static class FunctionVar implements Function {
private final Node var;
public FunctionVar(Node var) {
this.var = var;
}
public String getName() {
return var.getFirstChild().getString();
}
public Node getFunctionNode() {
return var.getFirstChild().getFirstChild();
}
public void remove() {
NodeUtil.removeChild(var.getParent(), var);
}
@Override
public Node getDeclaringBlock() {
return var.getParent();
}
}
/** FunctionExpression implementation of the Function interface */
private static class FunctionExpression implements Function {
private final Node fn;
private final String fake
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>. */
enum InliningMode {
/**
* Directly replace the call expression. Only functions of meeting
* strict preconditions can be inlined.
*/
DIRECT,
/**
* Replaces the call expression with a block of statements. Conditions
* on the function are looser in mode, but stricter on the call site.
*/
BLOCK
}
/** Holds a reference to the call node of a function call */
static class Reference {
final Node callNode;
final JSModule module;
final InliningMode mode;
Reference(Node callNode, JSModule module, InliningMode mode){
this.callNode = callNode;
this.module = module;
this.mode = mode;
}
}
/**
* In order to estimate the cost of lining, we make the assumption that
* Identifiers are reduced 2 characters. For the call arguments, the important
* thing is that the cost is assumed to be the same in the call and the
* function, so the actual length doesn't matter in most cases.
*/
private static final int NAME_COST_ESTIMATE =
InlineCostEstimator.ESTIMATED_IDENTIFIER_COST;
/** The cost of a argument separator (a comma). */
private static final int COMMA_COST = 1;
/** The cost of the parentheses needed to make a call.*/
private static final int PAREN_COST = 2;
/**
* @param fnName The name of this function. This either the name of the
* variable to which the function is assigned or the name from the FUNCTION
* node.
* @param fnNode The FUNCTION node of the function to inspect.
* @return Whether the function node meets the minimum requirements for
* inlining.
*/
boolean doesFunctionMeetMinimumRequirements(
String fnName, Node fnNode) {
Node block = NodeUtil.getFunctionBody(fnNode);
// Don't inline recursive functions, nor functions that contain
// 'this', 'arguments' references.
if (NodeUtil.isNameReferenced(block, fnName)) {
return false;
}
String fnRecursionName = fnNode.getFirstChild().getString();
if (fnRecursionName != null
&& !fnRecursionName.isEmpty()
&& !fnRecursionName.equals(fn
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> the
// reference object and passing it in here.
CallSiteType callSiteType = classifyCallSite(callNode);
Preconditions.checkArgument(callSiteType != CallSiteType.UNSUPPORTED);
// Store the name for the result. This will be used to
// replace "return expr" statements with "resultName = expr"
// to replace
String resultName = null;
boolean needsDefaultReturnResult = true;
switch (callSiteType) {
case SIMPLE_ASSIGNMENT:
resultName = parent.getFirstChild().getString();
break;
case VAR_DECL_SIMPLE_ASSIGNMENT:
resultName = parent.getString();
break;
case SIMPLE_CALL:
resultName = null; // "foo()" doesn't need a result.
needsDefaultReturnResult = false;
break;
case EXPRESSION:
resultName = getUniqueResultName();
needsDefaultReturnResult = false; // The intermediary result already
// has the default value.
break;
case DECOMPOSABLE_EXPRESSION:
throw new IllegalStateException(
"Decomposable expressions must decomposed before inlining.");
default:
throw new IllegalStateException("Unexpected call site type.");
}
boolean isCallInLoop = NodeUtil.isWithinLoop(callNode);
FunctionToBlockMutator mutator = new FunctionToBlockMutator(
compiler, this.safeNameIdSupplier);
Node newBlock = mutator.mutate(
fnName, fnNode, callNode, resultName,
needsDefaultReturnResult, isCallInLoop);
// TODO(nicksantos): Create a common mutation function that
// can replace either a VAR name assignment, assignment expression or
// a EXPR_RESULT.
Node greatGrandParent = grandParent.getParent();
switch (callSiteType) {
case VAR_DECL_SIMPLE_ASSIGNMENT:
// Remove the call from the name node.
parent.removeChild(parent.getFirstChild());
Preconditions.checkState(parent.getFirstChild() == null);
// Add the call, after the VAR.
greatGrandParent.addChildAfter(newBlock, grandParent);
break;
case SIMPLE_ASSIGNMENT:
// The assignment is now part of the inline function so
// replace it completely.
Preconditions.checkState(NodeUtil.isExpressionNode(grandParent));
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> {
if (NodeUtil.isFunctionObjectCall(callNode)) {
// TODO(johnlenz): Support replace this with a value.
Preconditions.checkNotNull(cArg);
Preconditions.checkState(cArg.getType() == Token.THIS);
cArg = cArg.getNext();
} else {
// ".apply" call should be filtered before this.
Preconditions.checkState(!NodeUtil.isFunctionObjectApply(callNode));
}
}
// FUNCTION NODE -> LP NODE: [ ARG1, ARG2, ... ]
Node fnParam = NodeUtil.getFnParameters(fnNode).getFirstChild();
while (cArg != null || fnParam != null) {
// For each named parameter check if a mutable argument use more than one.
if (fnParam != null) {
if (cArg != null) {
// Check for arguments that are evaluated more than once.
// Note: Unlike block inlining, there it is not possible that a
// parameter reference will be in a loop.
if (NodeUtil.mayEffectMutableState(cArg)
&& NodeUtil.getNameReferenceCount(
block, fnParam.getString()) > 1) {
return CanInlineResult.NO;
}
}
// Move to the next name.
fnParam = fnParam.getNext();
}
// For every call argument check for side-effects, even if there
// isn't a named parameter to match.
if (cArg != null) {
if (NodeUtil.mayHaveSideEffects(cArg)) {
return CanInlineResult.NO;
}
cArg = cArg.getNext();
}
}
return CanInlineResult.YES;
}
/**
* Parameter names will be name unique when at a later time.
*/
private String getUniqueResultName() {
return "JSCompiler_inline_result"
+ ContextualRenamer.UNIQUE_ID_SEPARATOR + safeNameIdSupplier.get();
}
/**
* Determine if inlining the function is likely to reduce the code size.
* @param namesToAlias
*/
boolean inliningLowersCost(
JSModule fnModule, Node fnNode, Collection<? extends Reference> refs,
Set<String> namesToAlias, boolean isRemovable, boolean referencesThis) {
int referenceCount = refs.size();
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> NodeTraversal.AbstractPostOrderCallback {
private final CodingConvention convention;
PrepareAnnotations(AbstractCompiler compiler) {
this.convention = compiler.getCodingConvention();
}
public void visit(NodeTraversal t, Node n, Node parent) {
switch (n.getType()) {
case Token.CALL:
annotateCalls(n);
break;
case Token.FUNCTION:
annotateFunctions(n, parent);
annotateDispatchers(n, parent);
break;
case Token.NAME:
case Token.STRING:
annotateConstants(n, parent);
break;
case Token.OBJECTLIT:
visitObjectLiteral(n);
break;
}
}
private void visitObjectLiteral(Node objlit) {
Preconditions.checkState(objlit.getType() == Token.OBJECTLIT);
for (Node key = objlit.getFirstChild();
key != null; key = key.getNext().getNext()) {
Node value = key.getNext();
visitObjectLiteralKey(objlit, key, value);
}
}
/**
* Prepare the object literal keys.
*/
private void visitObjectLiteralKey(Node objlit, Node key, Node value) {
normalizeObjectLitJsDocs(objlit, key, value);
annotateObjLitConstants(objlit, key, value);
}
/**
* There are two types of calls we are interested in calls without explicit
* "this" values (what we are call "free" calls) and direct call to eval.
*/
private void annotateCalls(Node n) {
Preconditions.checkState(n.getType() == Token.CALL);
// Keep track of of the "this" context of a call. A call without an
// explicit "this" is a free call.
Node first = n.getFirstChild();
if (!NodeUtil.isGet(first)) {
n.putBooleanProp(Node.FREE_CALL, true);
}
// Keep track of the context in which eval is called. It is important
// to distinguish between "(0, eval)()" and "eval()".
if (first.getType() == Token.NAME &&
"eval".equals(first.getString())) {
first.putBooleanProp(Node.DIRECT_EVAL, true);
}
}
/**
* Translate dispatcher info into the property expected node.
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>key.getType() == Token.NAME || key.getType() == Token.STRING) {
String name = key.getString();
if (convention.isConstantKey(name)) {
key.putBooleanProp(Node.IS_CONSTANT_NAME, true);
}
}
}
/**
* Annotate optional and var_arg function parameters.
*/
private void annotateFunctions(Node n, Node parent) {
JSDocInfo fnInfo = NodeUtil.getFunctionInfo(n);
// Compute which function parameters are optional and
// which are var_args.
Node args = n.getFirstChild().getNext();
for (Node arg = args.getFirstChild();
arg != null;
arg = arg.getNext()) {
String argName = arg.getString();
JSTypeExpression typeExpr = fnInfo == null ?
null : fnInfo.getParameterType(argName);
if (convention.isOptionalParameter(arg) ||
typeExpr != null && typeExpr.isOptionalArg()) {
arg.putBooleanProp(Node.IS_OPTIONAL_PARAM, true);
}
if (convention.isVarArgsParameter(arg) ||
typeExpr != null && typeExpr.isVarArgs()) {
arg.putBooleanProp(Node.IS_VAR_ARGS_PARAM, true);
}
}
}
}
}
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> found,
JSType required) {
return MessageFormat.format(FOUND_REQUIRED, description, found, required);
}
/**
* Given a node, get a human-readable name for the type of that node so
* that will be easy for the programmer to find the original declaration.
*
* For example, if SubFoo's property "bar" might have the human-readable
* name "Foo.prototype.bar".
*
* @param n The node.
* @param dereference If true, the type of the node will be dereferenced
* to an Object type, if possible.
*/
String getReadableJSTypeName(Node n, boolean dereference) {
// If we're analyzing a GETPROP, the property may be inherited by the
// prototype chain. So climb the prototype chain and find out where
// the property was originally defined.
if (n.getType() == Token.GETPROP) {
ObjectType objectType = getJSType(n.getFirstChild()).dereference();
if (objectType != null) {
String propName = n.getLastChild().getString();
while (objectType != null && !objectType.hasOwnProperty(propName)) {
objectType = objectType.getImplicitPrototype();
}
// Don't show complex function names or anonymous types.
// Instead, try to get a human-readable type name.
if (objectType != null &&
(objectType.getConstructor() != null ||
objectType.isFunctionPrototypeType())) {
return objectType.toString() + "." + propName;
}
}
}
JSType type = getJSType(n);
if (dereference) {
ObjectType dereferenced = type.dereference();
if (dereferenced != null) {
type = dereferenced;
}
}
String qualifiedName = n.getQualifiedName();
if (type.isFunctionPrototypeType() ||
(type.toObjectType() != null &&
type.toObjectType().getConstructor() != null)) {
return type.toString();
} else if (qualifiedName != null) {
return qualifiedName;
} else if (type instanceof FunctionType) {
// Don't show complex function names.
return "function";
} else {
return type.toString();
}
}
/**
* This method gets
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>)) {
ungetChar(c2);
this.string = getStringFromBuffer();
stringBufferTop = 0;
return JsDocToken.STRING;
} else {
do {
c1 = c2;
c2 = getChar();
if (c1 == '.' && c2 == '<') {
ungetChar(c2);
ungetChar(c1);
this.string = getStringFromBuffer();
stringBufferTop = 0;
return JsDocToken.STRING;
} else {
if (isJSDocString(c2)) {
addToString(c1);
} else {
ungetChar(c2);
addToString(c1);
this.string = getStringFromBuffer();
stringBufferTop = 0;
return JsDocToken.STRING;
}
}
} while (true);
}
}
}
}
}
/**
* Gets the remaining JSDoc line without the {@link JsDocToken#EOL},
* {@link JsDocToken#EOF} or {@link JsDocToken#EOC}.
*/
@SuppressWarnings("fallthrough")
String getRemainingJSDocLine() {
int c;
for (;;) {
c = getChar();
switch (c) {
case '*':
if (peekChar() != '/') {
addToString(c);
break;
}
// fall through
case EOF_CHAR:
case '\n':
ungetChar(c);
this.string = getStringFromBuffer();
stringBufferTop = 0;
return this.string;
default:
addToString(c);
break;
}
}
}
final int getLineno() { return lineno; }
final int getCharno() {
return lineno == initLineno? initCharno + charno : charno;
}
final String getString() { return string; }
final boolean eof() { return hitEOF; }
private String getStringFromBuffer() {
tokenEnd = cursor;
return new String(stringBuffer, 0, stringBufferTop);
}
private void addToString(int c) {
int N = stringBufferTop;
if (N == stringBuffer.length) {
char[] tmp = new char[stringBuffer.length * 2];
System.arraycopy(string
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>mayHaveSideEffects(operand)) {
n.removeFirstChild();
reportCodeChange();
}
break;
case Token.NAME:
String name = result.getString();
if (name.equals("undefined")) {
n.removeFirstChild();
reportCodeChange();
}
break;
default:
//Do nothing
break;
}
}
return n;
}
/**
* Try to minimize NOT nodes such as !(x==y).
*
* Returns the replacement for n or the original if no change was made
*/
private Node tryMinimizeNot(Node n) {
Node parent = n.getParent();
Node notChild = n.getFirstChild();
// negative operator of the current one : == -> != for instance.
int complementOperator;
switch (notChild.getType()) {
case Token.EQ:
complementOperator = Token.NE;
break;
case Token.NE:
complementOperator = Token.EQ;
break;
case Token.SHEQ:
complementOperator = Token.SHNE;
break;
case Token.SHNE:
complementOperator = Token.SHEQ;
break;
// GT, GE, LT, LE are not handled in this because !(x<NaN) != x>=NaN.
default:
return n;
}
Node newOperator = n.removeFirstChild();
newOperator.setType(complementOperator);
parent.replaceChild(n, newOperator);
reportCodeChange();
return newOperator;
}
/**
* Try turning IF nodes into smaller HOOKs
*
* Returns the replacement for n or the original if no replacement was
* necessary.
*/
private Node tryMinimizeIf(Node n) {
Node parent = n.getParent();
Node cond = n.getFirstChild();
/* If the condition is a literal, we'll let other
* optimizations try to remove useless code.
*/
if (NodeUtil.isLiteralValue(cond, true)) {
return n;
}
Node thenBranch = cond.getNext();
Node elseBranch = thenBranch.getNext();
if (elseBranch == null) {
if (isExpressBlock(thenBranch)) {
Node expr = getBlockExpression(thenBranch);
if (isPropertyAssignmentInExpression(expr)) {
// Keep opportunities for CollapseProperties
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>
return expr;
}
} else if (NodeUtil.isCall(thenOp)) {
// if(x)foo();else bar(); -> x?foo():bar()
n.removeChild(cond);
thenOp.detachFromParent();
elseOp.detachFromParent();
Node hookNode = new Node(Token.HOOK, cond, thenOp, elseOp)
.copyInformationFrom(n);
Node expr = NodeUtil.newExpr(hookNode);
parent.replaceChild(n, expr);
reportCodeChange();
return expr;
}
}
return n;
}
boolean thenBranchIsVar = isVarBlock(thenBranch);
boolean elseBranchIsVar = isVarBlock(elseBranch);
// if(x)var y=1;else y=2 -> var y=x?1:2
if (thenBranchIsVar && elseBranchIsExpressionBlock &&
NodeUtil.isAssign(getBlockExpression(elseBranch).getFirstChild())) {
Node var = getBlockVar(thenBranch);
Node elseAssign = getBlockExpression(elseBranch).getFirstChild();
Node name1 = var.getFirstChild();
Node maybeName2 = elseAssign.getFirstChild();
if (name1.hasChildren()
&& maybeName2.getType() == Token.NAME
&& name1.getString().equals(maybeName2.getString())) {
Node thenExpr = name1.removeChildren();
Node elseExpr = elseAssign.getLastChild().detachFromParent();
cond.detachFromParent();
Node hookNode = new Node(Token.HOOK, cond, thenExpr, elseExpr)
.copyInformationFrom(n);
var.detachFromParent();
name1.addChildrenToBack(hookNode);
parent.replaceChild(n, var);
reportCodeChange();
return var;
}
// if(x)y=1;else var y=2 -> var y=x?1:2
} else if (elseBranchIsVar && thenBranchIsExpressionBlock &&
NodeUtil.isAssign(getBlockExpression(thenBranch).getFirstChild())) {
Node var = getBlockVar(elseBranch);
Node thenAssign = getBlockExpression(thenBranch).getFirstChild();
Node maybeName1 = thenAssign.getFirstChild();
Node name2 = var.getFirstChild
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>();
if (name2.hasChildren()
&& maybeName1.getType() == Token.NAME
&& maybeName1.getString().equals(name2.getString())) {
Node thenExpr = thenAssign.getLastChild().detachFromParent();
Node elseExpr = name2.removeChildren();
cond.detachFromParent();
Node hookNode = new Node(Token.HOOK, cond, thenExpr, elseExpr)
.copyInformationFrom(n);
var.detachFromParent();
name2.addChildrenToBack(hookNode);
parent.replaceChild(n, var);
reportCodeChange();
return var;
}
}
return n;
}
/**
* Try to remove duplicate statements from IF blocks. For example:
*
* if (a) {
* x = 1;
* return true;
* } else {
* x = 2;
* return true;
* }
*
* becomes:
*
* if (a) {
* x = 1;
* } else {
* x = 2;
* }
* return true;
*
* @param n The IF node to examine.
*/
private void tryRemoveRepeatedStatements(Node n) {
Preconditions.checkState(n.getType() == Token.IF);
Node parent = n.getParent();
if (!NodeUtil.isStatementBlock(parent)) {
// If the immediate parent is something like a label, we
// can't move the statement, so bail.
return;
}
Node cond = n.getFirstChild();
Node trueBranch = cond.getNext();
Node falseBranch = trueBranch.getNext();
Preconditions.checkNotNull(trueBranch);
Preconditions.checkNotNull(falseBranch);
while (true) {
Node lastTrue = trueBranch.getLastChild();
Node lastFalse = falseBranch.getLastChild();
if (lastTrue == null || lastFalse == null
|| !areNodesEqualForInlining(lastTrue, lastFalse)) {
break;
}
lastTrue.detachFromParent();
lastFalse.detachFromParent();
parent.addChildAfter(lastTrue, n);
reportCodeChange();
}
}
/**
* @return Whether the node is a block with a single statement that is
* an expression.
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>n)) {
parent.replaceChild(n, newNode);
reportCodeChange();
return newNode;
}
return n;
}
private static final ImmutableSet<String> STANDARD_OBJECT_CONSTRUCTORS =
// String, Number, and Boolean functions return non-object types, whereas
// new String, new Number, and new Boolean return object types, so don't
// include them here.
ImmutableSet.of(
"Object",
"Array",
"RegExp",
"Error"
);
/**
* Fold "new Object()" to "Object()".
*/
private Node tryFoldStandardConstructors(Node n) {
Preconditions.checkState(n.getType() == Token.NEW);
// If name normalization has been run then we know that
// new Object() does in fact refer to what we think it is
// and not some custom-defined Object().
if (isASTNormalized()) {
if (n.getFirstChild().getType() == Token.NAME) {
String className = n.getFirstChild().getString();
if (STANDARD_OBJECT_CONSTRUCTORS.contains(className)) {
n.setType(Token.CALL);
reportCodeChange();
}
}
}
return n;
}
/**
* Replaces a new Array or Object node with an object literal, unless the
* call to Array or Object is to a local function with the same name.
*/
private Node tryFoldLiteralConstructor(Node n) {
Preconditions.checkArgument(n.getType() == Token.CALL
|| n.getType() == Token.NEW);
Node constructorNameNode = n.getFirstChild();
Node newLiteralNode = null;
// We require the AST to be normalized to ensure that, say,
// Object() really refers to the built-in Object constructor
// and not a user-defined constructor with the same name.
if (isASTNormalized() && Token.NAME == constructorNameNode.getType()) {
String className = constructorNameNode.getString();
if ("RegExp".equals(className)) {
// "RegExp("boo", "g")" --> /boo/g
return tryFoldRegularExpressionConstructor(n);
} else {
boolean constructorHasArgs = constructorNameNode.getNext() != null;
if ("Object".equals(className) && !constructorHasArgs) {
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>TO_FOLD_WITHOUT_ARGS;
}
break;
case (Token.ARRAYLIT):
// "Array([args])" --> "[[args]]"
action = FoldArrayAction.SAFE_TO_FOLD_WITH_ARGS;
break;
default:
}
}
return action;
}
private Node tryFoldRegularExpressionConstructor(Node n) {
Node parent = n.getParent();
Node constructor = n.getFirstChild();
Node pattern = constructor.getNext(); // e.g. ^foobar$
Node flags = null != pattern ? pattern.getNext() : null; // e.g. gi
// Only run on normalized AST to make sure RegExp() is actually
// the RegExp we expect (if the AST has been normalized then
// other RegExp's will have been renamed to something like RegExp$1)
if (!isASTNormalized()) {
return n;
}
if (null == pattern || (null != flags && null != flags.getNext())) {
// too few or too many arguments
return n;
}
if (// is pattern folded
pattern.getType() == Token.STRING
// make sure empty pattern doesn't fold to //
&& !"".equals(pattern.getString())
// NOTE(nicksantos): Make sure that the regexp isn't longer than
// 100 chars, or it blows up the regexp parser in Opera 9.2.
&& pattern.getString().length() < 100
&& (null == flags || flags.getType() == Token.STRING)
// don't escape patterns with unicode escapes since Safari behaves badly
// (read can't parse or crashes) on regex literals with unicode escapes
&& !containsUnicodeEscape(pattern.getString())) {
// Make sure that / is escaped, so that it will fit safely in /brackets/.
// pattern is a string value with \\ and similar already escaped
pattern = makeForwardSlashBracketSafe(pattern);
Node regexLiteral;
if (null == flags || "".equals(flags.getString())) {
// fold to /foobar/
regexLiteral = new Node(Token.REGEXP, pattern);
} else {
// fold to /foobar/gi
if (!areValidRegexpFlags(flags.getString())) {
error(INVALID_REGULAR_EXPRESSION_FLAGS, flags);
return n
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>;
}
if (!areSafeFlagsToFold(flags.getString())) {
return n;
}
n.removeChild(flags);
regexLiteral = new Node(Token.REGEXP, pattern, flags);
}
parent.replaceChild(n, regexLiteral);
reportCodeChange();
return regexLiteral;
}
return n;
}
private static final Pattern REGEXP_FLAGS_RE = Pattern.compile("^[gmi]*$");
/**
* are the given flags valid regular expression flags?
* Javascript recognizes several suffix flags for regular expressions,
* 'g' - global replace, 'i' - case insensitive, 'm' - multi-line.
* They are case insensitive, and javascript does not recognize the extended
* syntax mode, single-line mode, or expression replacement mode from perl5.
*/
private static boolean areValidRegexpFlags(String flags) {
return REGEXP_FLAGS_RE.matcher(flags).matches();
}
/**
* are the given flags safe to fold?
* We don't fold the regular expression if global ('g') flag is on,
* because in this case it isn't really a constant: its 'lastIndex'
* property contains the state of last execution, so replacing
* 'new RegExp('foobar','g')' with '/foobar/g' may change the behavior of
* the program if the RegExp is used inside a loop, for example.
*/
private static boolean areSafeFlagsToFold(String flags) {
return flags.indexOf('g') < 0;
}
/**
* returns a string node that can safely be rendered inside /brackets/.
*/
private static Node makeForwardSlashBracketSafe(Node n) {
String s = n.getString();
// sb contains everything in s[0:pos]
StringBuilder sb = null;
int pos = 0;
for (int i = 0; i < s.length(); ++i) {
switch (s.charAt(i)) {
case '\\': // skip over the next char after a '\\'.
++i;
break;
case '/': // escape it
if (null == sb) { sb = new StringBuilder(s.length() + 16); }
sb.append(s, pos, i).append('\\');
pos = i
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>Names = preserveFunctionExpressionNames;
}
/**
* Traverses the root, removing all unused variables. Multiple traversals
* may occur to ensure all unused variables are removed.
*/
public void process(Node externs, Node root) {
traverseAndRemoveUnusedReferences(root);
}
/**
* Traverses a node recursively. Call this once per pass.
*/
private void traverseAndRemoveUnusedReferences(Node root) {
Scope scope = new SyntacticScopeCreator(compiler).createScope(root, null);
traverseNode(root, null, scope);
if (removeGlobals) {
collectMaybeUnreferencedVars(scope);
}
interpretAssigns();
removeUnreferencedVars();
for (Scope fnScope : allFunctionScopes) {
removeUnreferencedFunctionArgs(fnScope);
}
}
/**
* Traverses everything in the current scope and marks variables that
* are referenced.
*
* During traversal, we identify subtrees that will only be
* referenced if their enclosing variables are referenced. Instead of
* traversing those subtrees, we create a continuation for them,
* and traverse them lazily.
*/
private void traverseNode(Node n, Node parent, Scope scope) {
int type = n.getType();
Var var = null;
switch (type) {
case Token.FUNCTION:
// If this function is a removable var, then create a continuation
// for it instead of traversing immediately.
if (NodeUtil.isFunctionDeclaration(n)) {
var = scope.getVar(n.getFirstChild().getString());
}
if (var != null && isRemovableVar(var)) {
continuations.put(var, new Continuation(n, scope));
} else {
traverseFunction(n, scope);
}
return;
case Token.ASSIGN:
Assign maybeAssign = Assign.maybeCreateAssign(n);
if (maybeAssign != null) {
// Put this in the assign map. It might count as a reference,
// but we won't know that until we have an index of all assigns.
var = scope.getVar(maybeAssign.nameNode.getString());
if (var != null) {
assignsByVar.put(var, maybeAssign);
assignsByNode.put(maybeAssign.name
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>Node, maybeAssign);
if (isRemovableVar(var) &&
!maybeAssign.mayHaveSecondarySideEffects) {
// If the var is unreferenced and performing this assign has
// no secondary side effects, then we can create a continuation
// for it instead of traversing immediately.
continuations.put(var, new Continuation(n, scope));
return;
}
}
}
break;
case Token.NAME:
var = scope.getVar(n.getString());
if (parent.getType() == Token.VAR) {
Node value = n.getFirstChild();
if (value != null && var != null && isRemovableVar(var) &&
!NodeUtil.mayHaveSideEffects(value)) {
// If the var is unreferenced and creating its value has no side
// effects, then we can create a continuation for it instead
// of traversing immediately.
continuations.put(var, new Continuation(n, scope));
return;
}
} else {
// All name references that aren't declarations or assigns
// are references to other vars.
if (var != null) {
// If that var hasn't already been marked referenced, then
// start tracking it. If this is an assign, do nothing
// for now.
if (isRemovableVar(var)) {
if (!assignsByNode.containsKey(n)) {
markReferencedVar(var);
}
} else {
markReferencedVar(var);
}
}
}
break;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
traverseNode(c, n, scope);
}
}
private boolean isRemovableVar(Var var) {
// Global variables are off-limits if the user might be using them.
if (!removeGlobals && var.isGlobal()) {
return false;
}
// Referenced variables are off-limits.
if (referenced.contains(var)) {
return false;
}
// Exported variables are off-limits.
if (compiler.getCodingConvention().isExported(var.getName())) {
return false;
}
return true;
}
/**
* Traverses a function, which creates a new scope in javascript.
*
*
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> Note that CATCH blocks also create a new scope, but only for the
* catch variable. Declarations within the block actually belong to the
* enclosing scope. Because we don't remove catch variables, there's
* no need to treat CATCH blocks differently like we do functions.
*/
private void traverseFunction(Node n, Scope parentScope) {
Preconditions.checkState(n.getChildCount() == 3);
Preconditions.checkState(n.getType() == Token.FUNCTION);
final Node body = n.getLastChild();
Preconditions.checkState(body.getNext() == null &&
body.getType() == Token.BLOCK);
Scope fnScope =
new SyntacticScopeCreator(compiler).createScope(n, parentScope);
traverseNode(body, n, fnScope);
collectMaybeUnreferencedVars(fnScope);
allFunctionScopes.add(fnScope);
}
/**
* For each variable in this scope that we haven't found a reference
* for yet, add it to the list of variables to check later.
*/
private void collectMaybeUnreferencedVars(Scope scope) {
for (Iterator<Var> it = scope.getVars(); it.hasNext(); ) {
Var var = it.next();
if (isRemovableVar(var)) {
maybeUnreferenced.add(var);
}
}
}
/**
* Removes unreferenced arguments from a function declaration.
*
* @param fnScope The scope inside the function
*/
private void removeUnreferencedFunctionArgs(Scope fnScope) {
// Strip unreferenced args off the end of the function declaration.
Node function = fnScope.getRootNode();
Preconditions.checkState(function.getType() == Token.FUNCTION);
Node argList = function.getFirstChild().getNext();
Node lastArg;
while ((lastArg = argList.getLastChild()) != null) {
Var var = fnScope.getVar(lastArg.getString());
if (!referenced.contains(var)) {
if (var == null) {
throw new IllegalStateException(
"Function parameter not declared in scope: "
+ lastArg.getString());
}
argList.removeChild(lastArg);
compiler.reportCodeChange();
} else {
break;
}
}
}
/**
* Look at all the property assigns to all variables.
*
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>();
// var foo = (a = b);
// In the first two cases, the sides of the assignment have side-effects.
// In the last one, the result of the assignment is used, so we
// are conservative and assume that it may be used in a side-effecting
// way.
final boolean mayHaveSecondarySideEffects;
Assign(Node assignNode, Node nameNode, boolean isPropertyAssign) {
Preconditions.checkState(NodeUtil.isAssignmentOp(assignNode));
this.assignNode = assignNode;
this.nameNode = nameNode;
this.isPropertyAssign = isPropertyAssign;
this.mayHaveSecondarySideEffects =
assignNode.getParent().getType() != Token.EXPR_RESULT ||
NodeUtil.mayHaveSideEffects(assignNode.getFirstChild()) ||
NodeUtil.mayHaveSideEffects(assignNode.getLastChild());
}
/**
* If this is an assign to a variable or its property, return it.
* Otherwise, return null.
*/
static Assign maybeCreateAssign(Node assignNode) {
Preconditions.checkState(NodeUtil.isAssignmentOp(assignNode));
// Skip one level of GETPROPs or GETELEMs.
//
// Don't skip more than one level, because then we get into
// situations where assigns to properties of properties will always
// trigger side-effects, and the variable they're on cannot be removed.
boolean isPropAssign = false;
Node current = assignNode.getFirstChild();
if (NodeUtil.isGet(current)) {
current = current.getFirstChild();
isPropAssign = true;
if (current.getType() == Token.GETPROP &&
current.getLastChild().getString().equals("prototype")) {
// Prototype properties sets should be considered like normal
// property sets.
current = current.getFirstChild();
}
}
if (current.getType() == Token.NAME) {
return new Assign(assignNode, current, isPropAssign);
}
return null;
}
/**
* Replace the current assign with its right hand side.
*/
void remove() {
Node parent = assignNode.getParent();
if (mayHaveSecondarySideEffects) {
Node replacement = assignNode.getLastChild().detachFromParent();
// Aggregate any expressions in GETE
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>DuplicateDeclarations runs after
// MakeDeclaredNamesUnique in order for catch block exception names to be
// handled properly. Specifically, catch block exception names are
// only valid within the catch block, but our currect Scope logic
// has no concept of this and includes it in the containing function
// (or global scope). MakeDeclaredNamesUnique makes the catch exception
// names unique so that removeDuplicateDeclarations() will properly handle
// cases where a function scope variable conflict with a exception name:
// function f() {
// try {throw 0;} catch(e) {e; /* catch scope 'e'*/}
// var e = 1; // f scope 'e'
// }
// otherwise 'var e = 1' would be rewritten as 'e = 1'.
// TODO(johnlenz): Introduce a seperate scope for catch nodes.
removeDuplicateDeclarations(externs, root);
new PropogateConstantAnnotations(compiler, assertOnChange)
.process(externs, root);
compiler.setNormalized();
}
public static class PropogateConstantAnnotations
extends AbstractPostOrderCallback
implements CompilerPass {
private final AbstractCompiler compiler;
private final boolean assertOnChange;
public PropogateConstantAnnotations(
AbstractCompiler compiler, boolean forbidChanges) {
this.compiler = compiler;
this.assertOnChange = forbidChanges;
}
@Override
public void process(Node externs, Node root) {
new NodeTraversal(compiler, this).traverseRoots(externs, root);
}
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
// Note: Constant properties annotations are not propagated.
if (n.getType() == Token.NAME) {
if (n.getString().isEmpty()) {
return;
}
JSDocInfo info = null;
// Find the JSDocInfo for a top level variable.
Var var = t.getScope().getVar(n.getString());
if (var != null) {
info = var.getJSDocInfo();
}
if ((info != null && info.isConstant()) &&
!n.getBooleanProp(Node.IS_CONSTANT_NAME)) {
n.putBooleanProp(Node.IS_CONSTANT_NAME, true);
if (assertOnChange
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>) {
String name = n.getString();
throw new IllegalStateException(
"Unexpected const change.\n" +
" name: "+ name + "\n" +
" gramps:" + n.getParent().getParent().toStringTree());
}
// Even though the AST has changed (an annotation was added),
// the annotations are not compared so don't report the change.
// reportCodeChange("constant annotation");
}
}
}
}
/**
* Walk the AST tree and verify that constant names are used consistently.
*/
static class VerifyConstants extends AbstractPostOrderCallback
implements CompilerPass {
final private AbstractCompiler compiler;
final private boolean checkUserDeclarations;
VerifyConstants(AbstractCompiler compiler, boolean checkUserDeclarations) {
this.compiler = compiler;
this.checkUserDeclarations = checkUserDeclarations;
}
@Override
public void process(Node externs, Node root) {
Node externsAndJs = root.getParent();
Preconditions.checkState(externsAndJs != null);
Preconditions.checkState(externsAndJs.hasChild(externs));
NodeTraversal.traverseRoots(
compiler, Lists.newArrayList(externs, root), this);
}
private Map<String,Boolean> constantMap = Maps.newHashMap();
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
if (n.getType() == Token.NAME) {
String name = n.getString();
if (n.getString().isEmpty()) {
return;
}
boolean isConst = n.getBooleanProp(Node.IS_CONSTANT_NAME);
if (checkUserDeclarations) {
boolean expectedConst = false;
CodingConvention convention = compiler.getCodingConvention();
if (NodeUtil.isConstantName(n)
|| NodeUtil.isConstantByConvention(convention, n, parent)) {
expectedConst = true;
} else {
expectedConst = false;
JSDocInfo info = null;
Var var = t.getScope().getVar(n.getString());
if (var != null) {
info = var.getJSDocInfo();
}
if (info != null && info.isConstant()) {
expectedConst = true;
} else {
expectedConst = false;
}
}
if (expectedConst) {
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>
return tryFoldAdd(subtree, left, right);
case Token.SUB:
case Token.MUL:
case Token.DIV:
return tryFoldArithmetic(subtree, left, right);
case Token.LT:
case Token.GT:
case Token.LE:
case Token.GE:
case Token.EQ:
case Token.NE:
case Token.SHEQ:
case Token.SHNE:
return tryFoldComparison(subtree, left, right);
default:
return subtree;
}
}
/**
* Folds 'typeof(foo)' if foo is a literal, e.g.
* typeof("bar") --> "string"
* typeof(6) --> "number"
*/
private Node tryFoldTypeof(Node originalTypeofNode) {
Preconditions.checkArgument(originalTypeofNode.getType() == Token.TYPEOF);
Node argumentNode = originalTypeofNode.getFirstChild();
if (argumentNode == null || !NodeUtil.isLiteralValue(argumentNode, true)) {
return originalTypeofNode;
}
String typeNameString = null;
switch (argumentNode.getType()) {
case Token.FUNCTION:
typeNameString = "function";
break;
case Token.STRING:
typeNameString = "string";
break;
case Token.NUMBER:
typeNameString = "number";
break;
case Token.TRUE:
case Token.FALSE:
typeNameString = "boolean";
break;
case Token.NULL:
case Token.OBJECTLIT:
case Token.ARRAYLIT:
typeNameString = "object";
break;
case Token.VOID:
typeNameString = "undefined";
break;
case Token.NAME:
// We assume here that programs don't change the value of the
// keyword undefined to something other than the value undefined.
if ("undefined".equals(argumentNode.getString())) {
typeNameString = "undefined";
}
break;
}
if (typeNameString != null) {
Node newNode = Node.newString(typeNameString);
originalTypeofNode.getParent().replaceChild(originalTypeofNode, newNode);
reportCodeChange();
return newNode;
}
return originalTypeofNode;
}
private Node tryFoldUnaryOperator(Node n) {
Preconditions.checkState(n.
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>hasOneChild());
Node left = n.getFirstChild();
Node parent = n.getParent();
if (left == null) {
return n;
}
TernaryValue leftVal = NodeUtil.getBooleanValue(left);
if (leftVal == TernaryValue.UNKNOWN) {
return n;
}
switch (n.getType()) {
case Token.NOT:
int result = leftVal.toBoolean(true) ? Token.FALSE : Token.TRUE;
Node replacementNode = new Node(result);
parent.replaceChild(n, replacementNode);
reportCodeChange();
return replacementNode;
case Token.NEG:
try {
if (left.getType() == Token.NAME) {
if (left.getString().equals("Infinity")) {
// "-Infinity" is valid and a literal, don't modify it.
return n;
} else if (left.getString().equals("NaN")) {
// "-NaN" is "NaN".
n.removeChild(left);
parent.replaceChild(n, left);
reportCodeChange();
return left;
}
}
double negNum = -left.getDouble();
Node negNumNode = Node.newNumber(negNum);
parent.replaceChild(n, negNumNode);
reportCodeChange();
return negNumNode;
} catch (UnsupportedOperationException ex) {
// left is not a number node, so do not replace, but warn the
// user because they can't be doing anything good
error(NEGATING_A_NON_NUMBER_ERROR, left);
return n;
}
case Token.BITNOT:
try {
double val = left.getDouble();
if (val >= Integer.MIN_VALUE && val <= Integer.MAX_VALUE) {
int intVal = (int) val;
if (intVal == val) {
Node notIntValNode = Node.newNumber(~intVal);
parent.replaceChild(n, notIntValNode);
reportCodeChange();
return notIntValNode;
} else {
error(FRACTIONAL_BITWISE_OPERAND, left);
return n;
}
} else {
error(BITWISE_OPERAND_OUT_OF_RANGE, left);
return n;
}
} catch (UnsupportedOperationException ex) {
// left
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> is not a number node, so do not replace, but warn the
// user because they can't be doing anything good
error(NEGATING_A_NON_NUMBER_ERROR, left);
return n;
}
default:
return n;
}
}
/**
* Try to fold {@code left instanceof right} into {@code true}
* or {@code false}.
*/
private Node tryFoldInstanceof(Node n, Node left, Node right) {
Preconditions.checkArgument(n.getType() == Token.INSTANCEOF);
// TODO(johnlenz) Use type information if available to fold
// instanceof.
if (NodeUtil.isLiteralValue(left, true)
&& !mayHaveSideEffects(right)) {
Node replacementNode = null;
if (NodeUtil.isImmutableValue(left)) {
// Non-object types are never instances.
replacementNode = new Node(Token.FALSE);
} else if (right.getType() == Token.NAME
&& "Object".equals(right.getString())) {
replacementNode = new Node(Token.TRUE);
}
if (replacementNode != null) {
n.getParent().replaceChild(n, replacementNode);
reportCodeChange();
return replacementNode;
}
}
return n;
}
private Node tryFoldAssign(Node n, Node left, Node right) {
Preconditions.checkArgument(n.getType() == Token.ASSIGN);
// Tries to convert x = x + y -> x += y;
if (!right.hasChildren() ||
right.getFirstChild().getNext() != right.getLastChild()) {
// RHS must have two children.
return n;
}
if (mayHaveSideEffects(left)) {
return n;
}
Node leftChild = right.getFirstChild();
if (!areNodesEqualForInlining(left, leftChild)) {
return n;
}
int newType = -1;
switch (right.getType()) {
case Token.ADD:
newType = Token.ASSIGN_ADD;
break;
case Token.BITAND:
newType = Token.ASSIGN_BITAND;
break;
case Token.BITOR:
newType = Token.ASSIGN_BITOR;
break;
case Token.BITXOR:
newType = Token.ASSIGN
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> result = lvalInt << rvalInt;
break;
case Token.RSH:
result = lvalInt >> rvalInt;
break;
case Token.URSH:
// JavaScript handles zero shifts on signed numbers differently than
// Java as an Java int can not represent the unsigned 32-bit number
// where JavaScript can so use a long here.
long lvalLong = lvalInt & 0xffffffffL;
result = lvalLong >>> rvalInt;
break;
default:
throw new AssertionError("Unknown shift operator: " +
Node.tokenToName(n.getType()));
}
Node newNumber = Node.newNumber(result);
n.getParent().replaceChild(n, newNumber);
reportCodeChange();
return newNumber;
}
return n;
}
/**
* Try to fold comparison nodes, e.g ==
*/
@SuppressWarnings("fallthrough")
private Node tryFoldComparison(Node n, Node left, Node right) {
if (!NodeUtil.isLiteralValue(left, false) ||
!NodeUtil.isLiteralValue(right, false)) {
// We only handle non-literal operands for LT and GT.
if (n.getType() != Token.GT && n.getType() != Token.LT) {
return n;
}
}
int op = n.getType();
boolean result;
// TODO(johnlenz): Use the JSType to compare nodes of different types.
boolean rightLiteral = NodeUtil.isLiteralValue(right, false);
boolean undefinedRight = ((Token.NAME == right.getType()
&& right.getString().equals("undefined"))
|| (Token.VOID == right.getType()
&& NodeUtil.isLiteralValue(right.getFirstChild(), false)));
switch (left.getType()) {
case Token.VOID:
if (!NodeUtil.isLiteralValue(left.getFirstChild(), false)) {
return n;
} else if (!rightLiteral) {
return n;
} else {
boolean nullRight = (Token.NULL == right.getType());
boolean equivalent = undefinedRight || nullRight;
switch (op) {
case Token.EQ:
// undefined is only equal to
result = equivalent;
break;
case Token.NE:
result = !equivalent;
break;
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>
case Token.SHEQ:
result = undefinedRight;
break;
case Token.SHNE:
result = !undefinedRight;
break;
case Token.LT:
case Token.GT:
case Token.LE:
case Token.GE:
result = false;
break;
default:
return n;
}
}
break;
case Token.NULL:
if (undefinedRight) {
result = (op == Token.EQ);
break;
}
// fall through
case Token.TRUE:
case Token.FALSE:
if (undefinedRight) {
result = false;
break;
}
// fall through
case Token.THIS:
int tt = right.getType();
if (tt != Token.THIS &&
tt != Token.TRUE &&
tt != Token.FALSE &&
tt != Token.NULL) {
return n;
}
switch (op) {
case Token.SHEQ:
case Token.EQ:
result = left.getType() == right.getType();
break;
case Token.SHNE:
case Token.NE:
result = left.getType() != right.getType();
break;
default:
return n; // we only handle == and != here
}
break;
case Token.STRING:
if (undefinedRight) {
result = false;
break;
}
if (Token.STRING != right.getType()) {
return n; // Only eval if they are the same type
}
switch (op) {
case Token.SHEQ:
case Token.EQ:
result = left.getString().equals(right.getString());
break;
case Token.SHNE:
case Token.NE:
result = !left.getString().equals(right.getString());
break;
default:
return n; // we only handle == and != here
}
break;
case Token.NUMBER:
if (undefinedRight) {
result = false;
break;
}
if (Token.NUMBER != right.getType()) {
return n; // Only eval if they are the same type
}
double lv = left.getDouble();
double rv = right.getDouble();
switch (op) {
case Token.SHEQ:
case Token.EQ: result = lv == rv; break;
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>
case Token.SHNE:
case Token.NE: result = lv != rv; break;
case Token.LE: result = lv <= rv; break;
case Token.LT: result = lv < rv; break;
case Token.GE: result = lv >= rv; break;
case Token.GT: result = lv > rv; break;
default:
return n; // don't handle that op
}
break;
case Token.NAME:
if (rightLiteral) {
boolean undefinedLeft = (left.getString().equals("undefined"));
if (undefinedLeft) {
boolean nullRight = (Token.NULL == right.getType());
boolean equivalent = undefinedRight || nullRight;
switch (op) {
case Token.EQ:
// undefined is only equal to
result = equivalent;
break;
case Token.NE:
result = !equivalent;
break;
case Token.SHEQ:
result = undefinedRight;
break;
case Token.SHNE:
result = !undefinedRight;
break;
case Token.LT:
case Token.GT:
case Token.LE:
case Token.GE:
result = false;
break;
default:
return n;
}
break;
}
}
if (Token.NAME != right.getType()) {
return n; // Only eval if they are the same type
}
String ln = left.getString();
String rn = right.getString();
if (!ln.equals(rn)) {
return n; // Not the same value name.
}
switch (op) {
// If we knew the named value wouldn't be NaN, it would be nice
// to handle EQ,NE,LE,GE,SHEQ, and SHNE.
case Token.LT:
case Token.GT:
result = false;
break;
default:
return n; // don't handle that op
}
break;
default:
// assert, this should cover all consts
return n;
}
Node newNode = new Node(result ? Token.TRUE : Token.FALSE);
n.getParent().replaceChild(n, newNode);
reportCodeChange();
return newNode;
}
/**
* Try to fold away unnecessary object instantiation.
* e.g. this[
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>new String('eval')] -> this.eval
*/
private Node tryFoldCtorCall(Node n) {
Preconditions.checkArgument(n.getType() == Token.NEW);
// we can remove this for GETELEM calls (anywhere else?)
if (inForcedStringContext(n)) {
return tryFoldInForcedStringContext(n);
}
return n;
}
/** Returns whether this node must be coerced to a string. */
private boolean inForcedStringContext(Node n) {
return n.getParent().getType() == Token.GETELEM &&
n.getParent().getLastChild() == n;
}
private Node tryFoldInForcedStringContext(Node n) {
// For now, we only know how to fold ctors.
Preconditions.checkArgument(n.getType() == Token.NEW);
Node objectType = n.getFirstChild();
if (objectType.getType() != Token.NAME) {
return n;
}
if (objectType.getString().equals("String")) {
Node value = objectType.getNext();
String stringValue = null;
if (value == null) {
stringValue = "";
} else {
if (!NodeUtil.isImmutableValue(value)) {
return n;
}
stringValue = NodeUtil.getStringValue(value);
}
if (stringValue == null) {
return n;
}
Node parent = n.getParent();
Node newString = Node.newString(stringValue);
parent.replaceChild(n, newString);
newString.copyInformationFrom(parent);
reportCodeChange();
return newString;
}
return n;
}
private Node tryFoldKnownMethods(Node subtree) {
// For now we only support .join() and .indexOf()
subtree = tryFoldStringJoin(subtree);
if (subtree.getType() == Token.CALL) {
subtree = tryFoldStringIndexOf(subtree);
}
return subtree;
}
/**
* Try to evaluate String.indexOf/lastIndexOf:
* "abcdef".indexOf("bc") -> 1
* "abcdefbc".indexOf("bc", 3) -> 6
*/
private Node tryFoldStringIndexOf(Node n) {
Preconditions.checkArgument(n.getType() == Token.CALL);
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>
Node left = n.getFirstChild();
if (left == null) {
return n;
}
Node right = left.getNext();
if (right == null) {
return n;
}
if (!NodeUtil.isGetProp(left) || !NodeUtil.isImmutableValue(right)) {
return n;
}
Node lstringNode = left.getFirstChild();
Node functionName = lstringNode.getNext();
if ((lstringNode.getType() != Token.STRING) ||
(!functionName.getString().equals("indexOf") &&
!functionName.getString().equals("lastIndexOf"))) {
return n;
}
String lstring = NodeUtil.getStringValue(lstringNode);
boolean isIndexOf = functionName.getString().equals("indexOf");
Node firstArg = right;
Node secondArg = right.getNext();
String searchValue = NodeUtil.getStringValue(firstArg);
// searchValue must be a valid string.
if (searchValue == null) {
return n;
}
int fromIndex = isIndexOf ? 0 : lstring.length();
if (secondArg != null) {
// Third-argument and non-numeric second arg are problematic. Discard.
if ((secondArg.getNext() != null) ||
(secondArg.getType() != Token.NUMBER)) {
return n;
} else {
fromIndex = (int) secondArg.getDouble();
}
}
int indexVal = isIndexOf ? lstring.indexOf(searchValue, fromIndex)
: lstring.lastIndexOf(searchValue, fromIndex);
Node newNode = Node.newNumber(indexVal);
n.getParent().replaceChild(n, newNode);
reportCodeChange();
return newNode;
}
/**
* Try to fold an array join: ['a', 'b', 'c'].join('') -> 'abc';
*/
private Node tryFoldStringJoin(Node n) {
Node left = n.getFirstChild();
if (left == null) {
return n;
}
Node right = left.getNext();
if (right == null) {
return n;
}
if (!NodeUtil.isGetProp(left) || !NodeUtil.isImmutableValue(right)) {
return n;
}
Node arrayNode = left.getFirstChild();
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>
Node functionName = arrayNode.getNext();
if ((arrayNode.getType() != Token.ARRAYLIT) ||
!functionName.getString().equals("join")) {
return n;
}
String joinString = NodeUtil.getStringValue(right);
List<Node> arrayFoldedChildren = Lists.newLinkedList();
StringBuilder sb = null;
int foldedSize = 0;
Node prev = null;
Node elem = arrayNode.getFirstChild();
// Merges adjacent String nodes.
while (elem != null) {
if (NodeUtil.isImmutableValue(elem)) {
if (sb == null) {
sb = new StringBuilder();
} else {
sb.append(joinString);
}
sb.append(NodeUtil.getStringValue(elem));
} else {
if (sb != null) {
Preconditions.checkNotNull(prev);
// + 2 for the quotes.
foldedSize += sb.length() + 2;
arrayFoldedChildren.add(
Node.newString(sb.toString()).copyInformationFrom(prev));
sb = null;
}
foldedSize += InlineCostEstimator.getCost(elem);
arrayFoldedChildren.add(elem);
}
prev = elem;
elem = elem.getNext();
}
if (sb != null) {
Preconditions.checkNotNull(prev);
// + 2 for the quotes.
foldedSize += sb.length() + 2;
arrayFoldedChildren.add(
Node.newString(sb.toString()).copyInformationFrom(prev));
}
// one for each comma.
foldedSize += arrayFoldedChildren.size() - 1;
int originalSize = InlineCostEstimator.getCost(n);
switch (arrayFoldedChildren.size()) {
case 0:
Node emptyStringNode = Node.newString("");
n.getParent().replaceChild(n, emptyStringNode);
reportCodeChange();
return emptyStringNode;
case 1:
Node foldedStringNode = arrayFoldedChildren.remove(0);
if (foldedSize > originalSize) {
return n;
}
arrayNode.detachChildren();
if (foldedStringNode.getType() != Token.STRING) {
// If the Node
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>elem);
n.getParent().replaceChild(n, elem);
reportCodeChange();
return elem;
}
return n;
}
/**
* Try to fold array-length. e.g [1, 2, 3].length ==> 3, [x, y].length ==> 2
*/
private Node tryFoldGetProp(Node n, Node left, Node right) {
Preconditions.checkArgument(n.getType() == Token.GETPROP);
if (right.getType() == Token.STRING &&
right.getString().equals("length")) {
int knownLength = -1;
switch (left.getType()) {
case Token.ARRAYLIT:
if (mayHaveSideEffects(left)) {
// Nope, can't fold this, without handling the side-effects.
return n;
}
knownLength = left.getChildCount();
break;
case Token.STRING:
knownLength = left.getString().length();
break;
default:
// Not a foldable case, forget it.
return n;
}
Preconditions.checkState(knownLength != -1);
Node lengthNode = Node.newNumber(knownLength);
n.getParent().replaceChild(n, lengthNode);
reportCodeChange();
return lengthNode;
}
return n;
}
}
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> next;
}
if (n.isSyntheticBlock() || n.getParent() == null) {
return n;
}
// Try to remove the block.
if (NodeUtil.tryMergeBlock(n)) {
reportCodeChange();
return null;
}
return n;
}
// TODO(johnlenz): Consider moving this to a separate peephole pass.
/**
* Attempt to replace the condition of if or hook immediately that is a
* reference to a name that is assigned immediately before.
*/
private void tryOptimizeConditionalAfterAssign(Node n) {
Node next = n.getNext();
// Look for patterns like the following and replace the if-condition with
// a constant value so it can later be folded:
// var a = /a/;
// if (a) {foo(a)}
// or
// a = 0;
// a ? foo(a) : c;
// or
// a = 0;
// a || foo(a);
// or
// a = 0;
// a && foo(a)
//
// TODO(johnlenz): This would be better handled by control-flow sensitive
// constant propagation. As the other case that I want to handle is:
// i=0; for(;i<0;i++){}
// as right now nothing facilitates removing a loop like that.
// This is here simply to remove the cruft left behind goog.userAgent and
// similar cases.
if (isSimpleAssignment(n) && isConditionalStatement(next)) {
Node lhsAssign = getSimpleAssignmentName(n);
Node condition = getConditionalStatementCondition(next);
if (NodeUtil.isName(lhsAssign) && NodeUtil.isName(condition)
&& lhsAssign.getString().equals(condition.getString())) {
Node rhsAssign = getSimpleAssignmentValue(n);
TernaryValue value = NodeUtil.getExpressionBooleanValue(rhsAssign);
if (value != TernaryValue.UNKNOWN) {
int replacementConditionNodeType =
(value.toBoolean(true)) ? Token.TRUE : Token.FALSE;
condition.getParent().replaceChild(condition,
new Node(replacementConditionNodeType));
reportCodeChange();
}
}
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> n, Node parent) {
if (n.getType() != Token.NAME) {
return;
}
String varName = n.getString();
// Only a function can have an empty name.
if (varName.isEmpty()) {
Preconditions.checkState(NodeUtil.isFunction(parent));
// A function declaration with an empty name passes Rhino,
// but is supposed to be a syntax error according to the spec.
if (!NodeUtil.isFunctionExpression(parent)) {
t.report(n, INVALID_FUNCTION_DECL);
}
return;
}
// Check if this is a declaration for a var that has been declared
// elsewhere. If so, mark it as a duplicate.
if ((parent.getType() == Token.VAR ||
NodeUtil.isFunctionDeclaration(parent)) &&
varsToDeclareInExterns.contains(varName)) {
createSynthesizedExternVar(varName);
parent.addSuppression("duplicate");
}
// Check that the var has been declared.
Scope scope = t.getScope();
Scope.Var var = scope.getVar(varName);
if (var == null) {
if (NodeUtil.isFunctionExpression(parent)) {
// e.g. [ function foo() {} ], it's okay if "foo" isn't defined in the
// current scope.
} else {
// The extern checks are stricter, don't report a second error.
if (!strictExternCheck || !t.getInput().isExtern()) {
t.report(n, UNDEFINED_VAR_ERROR, varName);
}
if (sanityCheck) {
throw new IllegalStateException("Unexpected variable " + varName);
} else {
createSynthesizedExternVar(varName);
scope.getGlobalScope().declare(varName, n,
null, getSynthesizedExternsInput());
}
}
return;
}
CompilerInput currInput = t.getInput();
CompilerInput varInput = var.input;
if (currInput == varInput || currInput == null || varInput == null) {
// The variable was defined in the same file. This is fine.
return;
}
// Check module dependencies.
JSModule currModule = currInput.getModule();
JSModule varModule = varInput.getModule();
JSModuleGraph moduleGraph =
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> public void visit(NodeTraversal t, Node n, Node parent) {
if (n.getType() == Token.NAME) {
switch (parent.getType()) {
case Token.VAR:
case Token.FUNCTION:
case Token.LP:
// These are okay.
break;
case Token.GETPROP:
if (n == parent.getFirstChild()) {
Scope scope = t.getScope();
Scope.Var var = scope.getVar(n.getString());
if (var == null) {
t.report(n, UNDEFINED_EXTERN_VAR_ERROR, n.getString());
varsToDeclareInExterns.add(n.getString());
}
}
break;
default:
t.report(n, NAME_REFERENCE_IN_EXTERNS_ERROR, n.getString());
Scope scope = t.getScope();
Scope.Var var = scope.getVar(n.getString());
if (var == null) {
varsToDeclareInExterns.add(n.getString());
}
break;
}
}
}
}
/** Lazily create a "new" externs input for undeclared variables. */
private CompilerInput getSynthesizedExternsInput() {
if (synthesizedExternsInput == null) {
synthesizedExternsInput =
compiler.newExternInput("{SyntheticVarsDeclar}");
}
return synthesizedExternsInput;
}
/** Lazily create a "new" externs root for undeclared variables. */
private Node getSynthesizedExternsRoot() {
if (synthesizedExternsRoot == null) {
CompilerInput synthesizedExterns = getSynthesizedExternsInput();
synthesizedExternsRoot = synthesizedExterns.getAstRoot(compiler);
}
return synthesizedExternsRoot;
}
}
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>.pseudoNameMap = Maps.newHashMap();
} else {
this.pseudoNameMap = null;
}
this.prevUsedRenameMap = prevUsedRenameMap;
this.reservedCharacters = reservedCharacters;
if (reservedNames == null) {
this.reservedNames = Sets.newHashSet();
} else {
this.reservedNames = Sets.newHashSet(reservedNames);
}
}
/**
* Iterate through the nodes, collect all the NAME nodes that need to be
* renamed, and count how many times each variable name is referenced.
*
* There are 2 passes:
* - externs: keep track of the global vars in the externNames_ map.
* - source: keep track of all name references in globalNameNodes_, and
* localNameNodes_.
*
* To get shorter local variable renaming, we rename local variables to a
* temporary name "LOCAL_VAR_PREFIX + index" where index is the index of the
* variable declared in the local scope stack.
* e.g.
* Foo(fa, fb) {
* var c = function(d, e) { return fa; }
* }
* The indexes are: fa:0, fb:1, c:2, d:3, e:4
*
* In that way, local variable names are reused in each global function.
* e.g. the final code might look like
* function x(a,b) { ... }
* function y(a,b,c) { ... }
*/
class ProcessVars extends AbstractPostOrderCallback {
private final boolean isExternsPass_;
ProcessVars(boolean isExterns) {
isExternsPass_ = isExterns;
}
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
if (n.getType() != Token.NAME) {
return;
}
String name = n.getString();
// Ignore anonymous functions
if (name.length() == 0) {
return;
}
// Is this local or Global?
Scope.Var var = t.getScope().getVar(name);
boolean local = (var != null) && var.isLocal();
// Are we renaming global variables?
if (!local && localRenamingOnly)
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> getNewGlobalName(Node n) {
String oldName = n.getString();
Assignment a = assignments.get(oldName);
if (a.newName != null && !a.newName.equals(oldName)) {
if (pseudoNameMap != null) {
return pseudoNameMap.get(n);
}
return a.newName;
} else {
return null;
}
}
private String getNewLocalName(Node n) {
String oldTempName = n.getString();
Assignment a = assignments.get(oldTempName);
if (!a.newName.equals(oldTempName)) {
if (pseudoNameMap != null) {
return pseudoNameMap.get(n);
}
return a.newName;
}
return null;
}
private void recordPseudoName(Node n) {
// Variable names should be in a different name space than
// property pseudo names.
pseudoNameMap.put(n, '$' + n.getString() + "$$" );
}
/**
* Runs through the assignments and reuses as many names as possible from the
* previously used variable map. Updates reservedNames with the set of names
* that were reused.
*/
private void reusePreviouslyUsedVariableMap() {
for (Assignment a : assignments.values()) {
String prevNewName = prevUsedRenameMap.lookupNewName(a.oldName);
if (prevNewName == null || reservedNames.contains(prevNewName)) {
continue;
}
if (a.oldName.startsWith(LOCAL_VAR_PREFIX) ||
(!externNames.contains(a.oldName) &&
prevNewName.startsWith(prefix))) {
reservedNames.add(prevNewName);
finalizeNameAssignment(a, prevNewName);
}
}
}
/**
* Determines which new names to substitute for the original names.
*/
private void assignNames(Set<Assignment> varsToRename) {
NameGenerator globalNameGenerator =
new NameGenerator(reservedNames, prefix, reservedCharacters);
// Local variables never need a prefix.
NameGenerator localNameGenerator = prefix.isEmpty() ?
globalNameGenerator : new NameGenerator(reservedNames, "",
reservedCharacters);
// Generated names and the assignments for non-local vars.
List<
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> * The stack of basic blocks and scopes the current traversal is in.
*/
private final Deque<BasicBlock> blockStack = new ArrayDeque<BasicBlock>();
/**
* Source of behavior at various points in the traversal.
*/
private final Behavior behavior;
/**
* Javascript compiler to use in traversing.
*/
private final AbstractCompiler compiler;
/**
* Only collect references for filtered variables.
*/
private final Predicate<Var> varFilter;
/**
* Constructor initializes block stack.
*/
ReferenceCollectingCallback(AbstractCompiler compiler, Behavior behavior) {
this(compiler, behavior, Predicates.<Var>alwaysTrue());
}
/**
* Constructor only collects references that match the given variable.
*
* The test for Var equality uses reference equality, so it's necessary to
* inject a scope when you traverse.
*/
ReferenceCollectingCallback(AbstractCompiler compiler, Behavior behavior,
Predicate<Var> varFilter) {
this.compiler = compiler;
this.behavior = behavior;
this.varFilter = varFilter;
}
/**
* Convenience method for running this pass over a tree with this
* class as a callback.
*/
public void process(Node externs, Node root) {
NodeTraversal.traverse(compiler, root, this);
}
/**
* Gets the variables that were referenced in this callback.
*/
public Set<Var> getReferencedVariables() {
return referenceMap.keySet();
}
/**
* Gets the reference collection for the given variable.
*/
public ReferenceCollection getReferenceCollection(Var v) {
return referenceMap.get(v);
}
/**
* For each node, update the block stack and reference collection
* as appropriate.
*/
public void visit(NodeTraversal t, Node n, Node parent) {
if (n.getType() == Token.NAME) {
Var v = t.getScope().getVar(n.getString());
if (v != null && varFilter.apply(v)) {
addReference(t, v,
new Reference(n, parent, t, blockStack.peek()));
}
}
if (isBlockBoundary(n, parent)) {
blockStack.pop();
}
}
/**
* Updates block stack and invokes any additional behavior.
*/
public void enterScope(
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> preciser scope to the next link.
* If there is no next link, returns the blind scope.
*/
protected FlowScope nextPreciserScopeKnowingConditionOutcome(Node condition,
FlowScope blindScope, boolean outcome) {
return nextLink != null ? nextLink.getPreciserScopeKnowingConditionOutcome(
condition, blindScope, outcome) : blindScope;
}
/**
* Returns the type of a node in the given scope if the node corresponds to a
* name whose type is capable of being refined.
* @return The current type of the node if it can be refined, null otherwise.
*/
JSType getTypeIfRefinable(Node node, FlowScope scope) {
switch (node.getType()) {
case Token.NAME:
StaticSlot<JSType> nameVar = scope.getSlot(node.getString());
if (nameVar != null) {
JSType nameVarType = nameVar.getType();
if (nameVarType == null) {
nameVarType = node.getJSType();
}
return nameVarType;
}
return null;
case Token.GETPROP:
String qualifiedName = node.getQualifiedName();
if (qualifiedName == null) {
return null;
}
StaticSlot<JSType> propVar = scope.getSlot(qualifiedName);
JSType propVarType = null;
if (propVar != null) {
propVarType = propVar.getType();
}
if (propVarType == null) {
propVarType = node.getJSType();
}
if (propVarType == null) {
propVarType = getNativeType(UNKNOWN_TYPE);
}
return propVarType;
}
return null;
}
/**
* Declares a refined type in {@code scope} for the name represented by
* {@code node}. It must be possible to refine the type of the given node in
* the given scope, as determined by {@link #getTypeIfRefinable}.
*/
protected void declareNameInScope(FlowScope scope, Node node, JSType type) {
switch (node.getType()) {
case Token.NAME:
scope.inferSlotType(node.getString(), type);
break;
case Token.GETPROP:
String qualifiedName
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>Scope();
final FunctionType functionType = (FunctionType) n.getJSType();
final String functionPrivateName = n.getFirstChild().getString();
if (functionPrivateName != null && functionPrivateName.length() > 0 &&
outerScope.isDeclared(functionPrivateName, false) &&
// Ideally, we would want to check whether the type in the scope
// differs from the type being defined, but then the extern
// redeclarations of built-in types generates spurious warnings.
!(outerScope.getVar(
functionPrivateName).getType() instanceof FunctionType)) {
report(t, n, FUNCTION_MASKS_VARIABLE, functionPrivateName);
}
// TODO(user): Only traverse the function's body. The function's
// name and arguments are traversed by the scope creator, and ideally
// should not be traversed by the type checker.
break;
}
return true;
}
/**
* This is the meat of the type checking. It is basically one big switch,
* with each case representing one type of parse tree node. The individual
* cases are usually pretty straightforward.
*
* @param t The node traversal object that supplies context, such as the
* scope chain to use in name lookups as well as error reporting.
* @param n The node being visited.
* @param parent The parent of the node n.
*/
public void visit(NodeTraversal t, Node n, Node parent) {
JSType childType;
JSType leftType, rightType;
Node left, right;
// To be explicitly set to false if the node is not typeable.
boolean typeable = true;
switch (n.getType()) {
case Token.NAME:
typeable = visitName(t, n, parent);
break;
case Token.LP:
// If this is under a FUNCTION node, it is a parameter list and can be
// ignored here.
if (parent.getType() != Token.FUNCTION) {
ensureTyped(t, n, getJSType(n.getFirstChild()));
} else {
typeable = false;
}
break;
case Token.COMMA:
ensureTyped(t, n, getJSType(n.getLastChild()));
break;
case Token.TRUE:
case Token.FALSE
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>Traversal t, Node assign) {
JSDocInfo info = assign.getJSDocInfo();
Node lvalue = assign.getFirstChild();
Node rvalue = assign.getLastChild();
if (lvalue.getType() == Token.GETPROP) {
Node object = lvalue.getFirstChild();
JSType objectJsType = getJSType(object);
String property = lvalue.getLastChild().getString();
// the first name in this getprop refers to an interface
// we perform checks in addition to the ones below
if (object.getType() == Token.GETPROP) {
JSType jsType = getJSType(object.getFirstChild());
if (jsType.isInterface() &&
object.getLastChild().getString().equals("prototype")) {
visitInterfaceGetprop(t, assign, object, property, lvalue, rvalue);
}
}
// /** @type ... */object.name = ...;
if (info != null && info.hasType()) {
visitAnnotatedAssignGetprop(t, assign,
info.getType().evaluate(t.getScope(), typeRegistry), object,
property, rvalue);
return;
}
// /** @enum ... */object.name = ...;
if (info != null && info.hasEnumParameterType()) {
checkEnumInitializer(
t, rvalue, info.getEnumParameterType().evaluate(
t.getScope(), typeRegistry));
return;
}
// object.prototype = ...;
if (property.equals("prototype")) {
if (objectJsType instanceof FunctionType) {
FunctionType functionType = (FunctionType) objectJsType;
if (functionType.isConstructor()) {
JSType rvalueType = rvalue.getJSType();
validator.expectObject(t, rvalue, rvalueType,
OVERRIDING_PROTOTYPE_WITH_NON_OBJECT);
}
} else {
// TODO(user): might want to flag that
}
return;
}
// object.prototype.property = ...;
if (object.getType() == Token.GETPROP) {
Node object2 = object.getFirstChild();
String property2 = NodeUtil.getStringValue(object.getLastChild());
if ("prototype".equals(property2)) {
JSType jsType = object2.getJSType();
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>
if (jsType instanceof FunctionType) {
FunctionType functionType = (FunctionType) jsType;
if (functionType.isConstructor() || functionType.isInterface()) {
checkDeclaredPropertyInheritance(
t, assign, functionType, property, info, getJSType(rvalue));
}
} else {
// TODO(user): might want to flag that
}
return;
}
}
// object.property = ...;
ObjectType type = ObjectType.cast(
objectJsType.restrictByNotNullOrUndefined());
if (type != null) {
if (type.hasProperty(property) &&
!type.isPropertyTypeInferred(property) &&
!propertyIsImplicitCast(type, property)) {
validator.expectCanAssignToPropertyOf(
t, assign, getJSType(rvalue),
type.getPropertyType(property), object, property);
}
return;
}
} else if (lvalue.getType() == Token.NAME) {
// variable with inferred type case
JSType rvalueType = getJSType(assign.getLastChild());
Var var = t.getScope().getVar(lvalue.getString());
if (var != null) {
if (var.isTypeInferred()) {
return;
}
}
}
// fall through case
JSType leftType = getJSType(lvalue);
Node rightChild = assign.getLastChild();
JSType rightType = getJSType(rightChild);
if (validator.expectCanAssignTo(
t, assign, rightType, leftType, "assignment")) {
ensureTyped(t, assign, rightType);
} else {
ensureTyped(t, assign);
}
}
/**
* Returns true if any type in the chain has an implictCast annotation for
* the given property.
*/
private boolean propertyIsImplicitCast(ObjectType type, String prop) {
for (; type != null; type = type.getImplicitPrototype()) {
JSDocInfo docInfo = type.getOwnPropertyJSDocInfo(prop);
if (docInfo != null && docInfo.isImplicitCast()) {
return true;
}
}
return false;
}
/**
* Given a constructor type and a property name, check that the property has
* the JSDoc annotation @override
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>JSType();
if (type == null) {
type = getNativeType(UNKNOWN_TYPE);
Var var = t.getScope().getVar(n.getString());
if (var != null) {
JSType varType = var.getType();
if (varType != null) {
type = varType;
}
}
}
ensureTyped(t, n, type);
return true;
}
/**
* Visits a GETPROP node.
*
* @param t The node traversal object that supplies context, such as the
* scope chain to use in name lookups as well as error reporting.
* @param n The node being visited.
* @param parent The parent of <code>n</code>
*/
private void visitGetProp(NodeTraversal t, Node n, Node parent) {
// GETPROP nodes have an assigned type on their node by the scope creator
// if this is an enum declaration. The only namespaced enum declarations
// that we allow are of the form object.name = ...;
if (n.getJSType() != null && parent.getType() == Token.ASSIGN) {
return;
}
// obj.prop or obj.method()
// Lots of types can appear on the left, a call to a void function can
// never be on the left. getPropertyType will decide what is acceptable
// and what isn't.
Node property = n.getLastChild();
Node objNode = n.getFirstChild();
JSType childType = getJSType(objNode);
// TODO(user): remove in favor of flagging every property access on
// non-object.
if (!validator.expectNotVoid(t, n, childType,
"undefined has no properties", getNativeType(OBJECT_TYPE))) {
ensureTyped(t, n);
return;
}
checkPropertyAccess(childType, property.getString(), t, n);
ensureTyped(t, n);
}
/**
* Make sure that the access of this property is ok.
*/
private void checkPropertyAccess(JSType childType, String propName,
NodeTraversal t, Node n) {
ObjectType objectType = childType.dereference();
if (objectType != null) {
JSType propType = getJSType(n);
if ((!
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> n.getLastChild();
validator.expectIndexMatch(t, n, getJSType(left), getJSType(right));
ensureTyped(t, n);
}
/**
* Visits a VAR node.
*
* @param t The node traversal object that supplies context, such as the
* scope chain to use in name lookups as well as error reporting.
* @param n The node being visited.
*/
private void visitVar(NodeTraversal t, Node n) {
// TODO(nicksantos): Fix this so that the doc info always shows up
// on the NAME node. We probably want to wait for the parser
// merge to fix this.
JSDocInfo varInfo = n.hasOneChild() ? n.getJSDocInfo() : null;
for (Node name : n.children()) {
Node value = name.getFirstChild();
// A null var would indicate a bug in the scope creation logic.
Var var = t.getScope().getVar(name.getString());
if (value != null) {
JSType valueType = getJSType(value);
JSType nameType = var.getType();
nameType = (nameType == null) ? getNativeType(UNKNOWN_TYPE) : nameType;
JSDocInfo info = name.getJSDocInfo();
if (info == null) {
info = varInfo;
}
if (info != null && info.hasEnumParameterType()) {
// var.getType() can never be null, this would indicate a bug in the
// scope creation logic.
checkEnumInitializer(
t, value,
info.getEnumParameterType().evaluate(t.getScope(), typeRegistry));
} else if (var.isTypeInferred()) {
ensureTyped(t, name, valueType);
} else {
validator.expectCanAssignTo(
t, value, valueType, nameType, "initializing variable");
}
}
}
}
/**
* Visits a NEW node.
*/
private void visitNew(NodeTraversal t, Node n) {
Node constructor = n.getFirstChild();
FunctionType type = getFunctionType(constructor);
if (type != null && type.isConstructor()) {
visitParameterList(t, n, type);
ensureTyped(t,
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> n, type.getInstanceType());
} else {
// TODO(user): add support for namespaced objects.
if (constructor.getType() != Token.GETPROP) {
// TODO(user): make the constructor node have lineno/charno
// and use constructor for a more precise error indication.
// It seems that GETPROP nodes are missing this information.
Node line;
if (constructor.getLineno() < 0 || constructor.getCharno() < 0) {
line = n;
} else {
line = constructor;
}
report(t, line, NOT_A_CONSTRUCTOR);
}
ensureTyped(t, n);
}
}
/**
* Visits a {@link Token#FUNCTION} node.
*
* @param t The node traversal object that supplies context, such as the
* scope chain to use in name lookups as well as error reporting.
* @param n The node being visited.
*/
private void visitFunction(NodeTraversal t, Node n) {
JSDocInfo info = n.getJSDocInfo();
FunctionType functionType = (FunctionType) n.getJSType();
String functionPrivateName = n.getFirstChild().getString();
if (functionType.isInterface() || functionType.isConstructor()) {
FunctionType baseConstructor = functionType.
getPrototype().getImplicitPrototype().getConstructor();
if (baseConstructor != null &&
baseConstructor != getNativeType(OBJECT_FUNCTION_TYPE) &&
(baseConstructor.isConstructor() && functionType.isInterface() ||
baseConstructor.isInterface() && functionType.isConstructor())) {
compiler.report(
t.makeError(n, CONFLICTING_EXTENDED_TYPE, functionPrivateName));
}
for (JSType baseInterface : functionType.getImplementedInterfaces()) {
boolean badImplementedType = false;
ObjectType baseInterfaceObj = ObjectType.cast(baseInterface);
if (baseInterfaceObj != null) {
FunctionType interfaceConstructor =
baseInterfaceObj.getConstructor();
if (interfaceConstructor != null &&
!interfaceConstructor.isInterface()) {
badImplementedType = true;
}
} else {
badImplementedType = true;
}
if (badImplementedType) {
report(t, n, BAD_IMPLEMENTED_TYPE
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>Typed(t, n, getNativeType(UNKNOWN_TYPE));
}
private void ensureTyped(NodeTraversal t, Node n, JSTypeNative type) {
ensureTyped(t, n, getNativeType(type));
}
/**
* Enforces type casts, and ensures the node is typed.
*
* A cast in the way that we use it in JSDoc annotations never
* alters the generated code and therefore never can induce any runtime
* operation. What this means is that a 'cast' is really just a compile
* time constraint on the underlying value. In the future, we may add
* support for run-time casts for compiled tests.
*
* To ensure some shred of sanity, we enforce the notion that the
* type you are casting to may only meaningfully be a narrower type
* than the underlying declared type. We also invalidate optimizations
* on bad type casts.
*
* @param t The traversal object needed to report errors.
* @param n The node getting a type assigned to it.
* @param type The type to be assigned.
*/
private void ensureTyped(NodeTraversal t, Node n, JSType type) {
// Make sure FUNCTION nodes always get function type.
Preconditions.checkState(n.getType() != Token.FUNCTION ||
type instanceof FunctionType ||
type.isUnknownType());
JSDocInfo info = n.getJSDocInfo();
if (info != null) {
if (info.hasType()) {
JSType infoType = info.getType().evaluate(t.getScope(), typeRegistry);
validator.expectCanCast(t, n, infoType, type);
type = infoType;
}
if (info.isImplicitCast() && !inExterns) {
String propName = n.getType() == Token.GETPROP ?
n.getLastChild().getString() : "(missing)";
compiler.report(
t.makeError(n, ILLEGAL_IMPLICIT_CAST, propName));
}
}
if (n.getJSType() == null) {
n.setJSType(type);
}
}
/**
* Returns the percentage of nodes typed by the type checker.
* @return a number between 0.0 and 100
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback;
import com.google.javascript.rhino.Token;
import com.google.javascript.rhino.Node;
/**
* Look for references to the global RegExp object that would cause
* regular expressions to be unoptimizable.
*
* @author johnlenz@google.com (John Lenz)
*/
class CheckRegExp extends AbstractPostOrderCallback implements CompilerPass {
static final DiagnosticType REGEXP_REFERENCE =
DiagnosticType.warning("JSC_REGEXP_REFERENCE",
"References to the global RegExp object prevents " +
"optimization of regular expressions.");
private final AbstractCompiler compiler;
private boolean globalRegExpPropertiesUsed = false;
public boolean isGlobalRegExpPropertiesUsed() {
return globalRegExpPropertiesUsed;
}
public CheckRegExp(AbstractCompiler compiler) {
this.compiler = compiler;
}
@Override
public void process(Node externs, Node root) {
NodeTraversal.traverse(compiler, root, this);
}
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
if (NodeUtil.isReferenceName(n)) {
String name = n.getString();
if (name.equals("RegExp") && t.getScope().getVar(name) == null) {
int parentType = parent.getType();
boolean first = (n == parent.getFirstChild());
if (!((parentType == Token.NEW && first)
|| (parentType == Token.CALL && first)
|| (parentType == Token.INSTANCEOF && !
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>.javascript.jscomp.mozilla.rhino.ast.TryStatement;
import com.google.javascript.jscomp.mozilla.rhino.ast.UnaryExpression;
import com.google.javascript.jscomp.mozilla.rhino.ast.VariableDeclaration;
import com.google.javascript.jscomp.mozilla.rhino.ast.VariableInitializer;
import com.google.javascript.jscomp.mozilla.rhino.ast.WhileLoop;
import com.google.javascript.jscomp.mozilla.rhino.ast.WithStatement;
import com.google.javascript.rhino.JSDocInfo;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.Token;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
/**
* IRFactory transforms the new AST to the old AST.
*
*/
public class IRFactory {
private final String sourceString;
private final String sourceName;
private final Config config;
private final ErrorReporter errorReporter;
private final TransformDispatcher transformDispatcher;
// non-static for thread safety
private final Set<String> ALLOWED_DIRECTIVES = Sets.newHashSet("use strict");
// Nodes with JSDoc comments, indexed by the text of the JSDoc comment.
//
// It's likely that two or more nodes in the same file may have the same
// jsdoc comment. In general, that's ok.
//
// There's one edge case where this might cause problems. If two JSDoc
// comments have the same text, and the first JSDoc comment is not attached
// to a node, then the second node will get the first JSDoc comment
// instead of the second. When this happens, it probably won't cause any
// problems. The two JSDoc comments will be exactly the same, except for
// their line numbers. Their line numbers will only be exposed for
// type name resolution warnings.
//
// TODO(nicksantos): Change rhino to put the whole Comment object
// on the Node.
private final Multimap<String, NodeWithJsDoc> nodesWithJsDoc =
LinkedHashMultimap.create();
// Use a template node for properties set on all nodes to minimize
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> the
// memory footprint associated with these.
private Node templateNode;
// TODO(johnlenz): Consider creating a template pool for ORIGINALNAME_PROP.
private IRFactory(String sourceString,
String sourceName,
Config config,
ErrorReporter errorReporter) {
this.sourceString = sourceString;
this.sourceName = sourceName;
this.config = config;
this.errorReporter = errorReporter;
this.transformDispatcher = new TransformDispatcher();
// The template node properties are applied to all nodes in this transform.
this.templateNode = createTemplateNode();
}
// Create a template node to use as a source of common attributes, this allows
// the prop structure to be shared among all the node from this source file.
// This reduces the cost of these properties to O(nodes) to O(files).
private Node createTemplateNode() {
// The Node type choice is arbitrary.
Node templateNode = new Node(Token.SCRIPT);
templateNode.putProp(Node.SOURCENAME_PROP, sourceName);
return templateNode;
}
public static Node transformTree(AstRoot node,
String sourceString,
Config config,
ErrorReporter errorReporter) {
IRFactory irFactory = new IRFactory(sourceString, node.getSourceName(),
config, errorReporter);
Node irNode = irFactory.transform(node);
// @license text gets appended onto the fileLevelJsDocBuilder as found,
// and stored straight into the JSDocInfo for the root node.
Node.FileLevelJsDocBuilder fileLevelJsDocBuilder =
irNode.getJsDocBuilderForNode();
// fileOverviewInfo stores the last bit of fileoverview data we saw.
// We only permit one, so throwing away extras is fair.
// The fileOverviewInfo gets passed into parseJSDocInfo so that
// it can detect when multiple @fileoverviews exist in the same file.
JSDocInfo fileOverviewInfo = null;
if (node.getComments() != null) {
for (Comment comment : node.getComments()) {
if (comment.getCommentType() == JSDOC) {
JsDocInfoParser jsDocParser =
irFactory.createJsDocInfoParser(comment.getValue(),
comment.getLineno(), comment.getAbsolutePosition
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>() != -1) {
irNode.setLineno(irNode.getFirstChild().getLineno());
irNode.setCharno(irNode.getFirstChild().getCharno());
} else {
if (irNode.getLineno() == -1) {
// If we didn't already set the line, then set it now. This avoids
// cases like ParenthesizedExpression where we just return a previous
// node, but don't want the new node to get its parent's line number.
int lineno = node.getLineno();
irNode.setLineno(lineno);
int charno = position2charno(node.getAbsolutePosition());
irNode.setCharno(charno);
}
}
return irNode;
}
/**
* Creates a JsDocInfoParser and parses the JsDoc string.
*
* Used both for handling individual JSDoc comments and for handling
* file-level JSDoc comments (@fileoverview and @license).
*
* @param comment The JsDoc comment to parse.
* @param lineno The line number of the node this comment is attached to.
* @param fileLevelJsDocBuilder The builder for file-level JSDocInfo.
* @param fileOverviewInfo The current @fileoverview JSDocInfo, so that the
* parser may warn if another @fileoverview is found. May be null.
* @return A JSDocInfoParser. Will contain either fileoverview jsdoc, or
* normal jsdoc, or no jsdoc (if the method parses to the wrong level).
*/
private JsDocInfoParser createJsDocInfoParser(
String comment, int lineno, int position,
Node.FileLevelJsDocBuilder fileLevelJsDocBuilder,
JSDocInfo fileOverviewInfo) {
// The JsDocInfoParser expects the comment without the initial '/**'.
int numOpeningChars = 3;
JsDocInfoParser jsdocParser =
new JsDocInfoParser(
new JsDocTokenStream(comment.substring(numOpeningChars),
lineno,
position2charno(position) + numOpeningChars),
sourceName,
config,
errorReporter);
jsdocParser.setFileLevelJsDocBuilder(fileLevelJsDocBuilder);
jsdocParser.setFileOverviewJSDoc
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>.STRING);
}
return ret;
}
@Override
Node processArrayLiteral(ArrayLiteral literalNode) {
if (literalNode.isDestructuring()) {
reportDestructuringAssign(literalNode);
}
Node node = newNode(Token.ARRAYLIT);
int skipCount = 0;
for (AstNode child : literalNode.getElements()) {
Node c = transform(child);
if (c.getType() == Token.EMPTY) {
skipCount++;
}
node.addChildToBack(c);
}
if (skipCount > 0) {
int[] skipIndexes = new int[skipCount];
int i = 0;
int j = 0;
for (Node child : node.children()) {
if (child.getType() == Token.EMPTY) {
node.removeChild(child);
skipIndexes[j] = i;
j++;
}
i++;
}
node.putProp(Node.SKIP_INDEXES_PROP, skipIndexes);
}
return node;
}
@Override
Node processAssignment(Assignment assignmentNode) {
return processInfixExpression(assignmentNode);
}
@Override
Node processAstRoot(AstRoot rootNode) {
Node node = newNode(Token.SCRIPT);
for (com.google.javascript.jscomp.mozilla.rhino.Node child : rootNode) {
node.addChildToBack(transform((AstNode)child));
}
parseDirectives(node);
return node;
}
/**
* Parse the directives, encode them in the AST, and remove their nodes.
*
* For information on ES5 directives, see section 14.1 of
* Ecma-262, Edition 5.
*
* It would be nice if Rhino would eventually take care of this for
* us, but right now their directive-processing is a one-off.
*/
private void parseDirectives(Node node) {
// Remove all the directives, and encode them in the AST.
Set<String> directives = null;
while (isDirective(node.getFirstChild())) {
String directive = node.removeFirstChild().getFirstChild().getString();
if (directives == null) {
directives = Sets.newHashSet(directive);
} else {
directives.
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>add(directive);
}
}
if (directives != null) {
node.setDirectives(directives);
}
}
private boolean isDirective(Node n) {
if (n == null) return false;
int nType = n.getType();
return (nType == Token.EXPR_RESULT || nType == Token.EXPR_VOID) &&
n.getFirstChild().getType() == Token.STRING &&
ALLOWED_DIRECTIVES.contains(n.getFirstChild().getString());
}
@Override
Node processBlock(Block blockNode) {
return processGeneric(blockNode);
}
@Override
Node processBreakStatement(BreakStatement statementNode) {
Node node = newNode(Token.BREAK);
if (statementNode.getBreakLabel() != null) {
Node labelName = transform(statementNode.getBreakLabel());
// Change the NAME to LABEL_NAME
labelName.setType(Token.LABEL_NAME);
node.addChildToBack(labelName);
}
return node;
}
@Override
Node processCatchClause(CatchClause clauseNode) {
AstNode catchVar = clauseNode.getVarName();
Node node = newNode(Token.CATCH, transform(catchVar));
if (clauseNode.getCatchCondition() != null) {
errorReporter.error(
"Catch clauses are not supported",
sourceName,
clauseNode.getCatchCondition().getLineno(), "", 0);
}
node.addChildToBack(transformBlock(clauseNode.getBody()));
return node;
}
@Override
Node processConditionalExpression(ConditionalExpression exprNode) {
return newNode(
Token.HOOK,
transform(exprNode.getTestExpression()),
transform(exprNode.getTrueExpression()),
transform(exprNode.getFalseExpression()));
}
@Override
Node processContinueStatement(ContinueStatement statementNode) {
Node node = newNode(Token.CONTINUE);
if (statementNode.getLabel() != null) {
Node labelName = transform(statementNode.getLabel());
// Change the NAME to LABEL_NAME
labelName.setType(Token.LABEL_NAME);
node.addChildToBack(labelName);
}
return node;
}
@Override
Node processDoLoop(DoLoop loopNode) {
return newNode(
Token.DO,
transformBlock
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>
isUnhoistedNamedFunction = true;
}
}
for (Reference reference : references) {
if (reference == hoistedFn) {
continue;
}
BasicBlock basicBlock = reference.getBasicBlock();
boolean isDeclaration = reference.isDeclaration();
if (isDeclaration) {
// Look through all the declarations we've found so far, and
// check if any of them are before this block.
for (BasicBlock declaredBlock : blocksWithDeclarations) {
if (declaredBlock.provablyExecutesBefore(basicBlock)) {
compiler.report(
JSError.make(reference.getSourceName(),
reference.getNameNode(),
checkLevel,
REDECLARED_VARIABLE, v.name));
break;
}
}
}
if (isUnhoistedNamedFunction && !isDeclaration && isDeclaredInScope) {
// Only allow an unhoisted named function to be used within the
// block it is declared.
for (BasicBlock declaredBlock : blocksWithDeclarations) {
if (!declaredBlock.provablyExecutesBefore(basicBlock)) {
compiler.report(
JSError.make(reference.getSourceName(),
reference.getNameNode(),
AMBIGUOUS_FUNCTION_DECL, v.name));
break;
}
}
}
if (!isDeclaration && !isDeclaredInScope) {
// Special case to deal with var goog = goog || {}
Node grandparent = reference.getGrandparent();
if (grandparent.getType() == Token.NAME
&& grandparent.getString() == v.name) {
continue;
}
// Only generate warnings if the scopes do not match in order
// to deal with possible forward declarations and recursion
if (reference.getScope() == v.scope) {
compiler.report(
JSError.make(reference.getSourceName(),
reference.getNameNode(),
checkLevel,
UNDECLARED_REFERENCE, v.name));
}
}
if (isDeclaration) {
blocksWithDeclarations.add(basicBlock);
isDeclaredInScope = true;
}
}
}
}
}
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>/*
* Copyright 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.Token;
/**
* Converts property accesses from quoted string syntax to dot syntax, where
* possible. Dot syntax is more compact and avoids an object allocation in
* IE 6.
*
*/
class ConvertToDottedProperties extends AbstractPostOrderCallback
implements CompilerPass {
private final AbstractCompiler compiler;
ConvertToDottedProperties(AbstractCompiler compiler) {
this.compiler = compiler;
}
@Override
public void process(Node externs, Node root) {
NodeTraversal.traverse(compiler, root, this);
}
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
switch (n.getType()) {
case Token.GETELEM:
Node left = n.getFirstChild();
Node right = left.getNext();
if (right.getType() == Token.STRING &&
NodeUtil.isValidPropertyName(right.getString())) {
n.removeChild(left);
n.removeChild(right);
parent.replaceChild(n, new Node(Token.GETPROP, left, right));
compiler.reportCodeChange();
}
break;
}
}
}
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>Compiler compiler, RedeclarationHandler redeclarationHandler) {
this.compiler = compiler;
this.redeclarationHandler = redeclarationHandler;
}
public Scope createScope(Node n, Scope parent) {
sourceName = null;
if (parent == null) {
scope = new Scope(n, compiler);
} else {
scope = new Scope(parent, n);
}
scanRoot(n, parent);
sourceName = null;
Scope returnedScope = scope;
scope = null;
return returnedScope;
}
private void scanRoot(Node n, Scope parent) {
if (n.getType() == Token.FUNCTION) {
sourceName = (String) n.getProp(Node.SOURCENAME_PROP);
final Node fnNameNode = n.getFirstChild();
final Node args = fnNameNode.getNext();
final Node body = args.getNext();
// Bleed the function name into the scope, if it hasn't
// been declared in the outer scope.
String fnName = fnNameNode.getString();
if (!fnName.isEmpty() && NodeUtil.isFunctionExpression(n)) {
declareVar(fnName, fnNameNode, n, null, null, n);
}
// Args: Declare function variables
Preconditions.checkState(args.getType() == Token.LP);
for (Node a = args.getFirstChild(); a != null;
a = a.getNext()) {
Preconditions.checkState(a.getType() == Token.NAME);
declareVar(a.getString(), a, args, n, null, n);
}
// Body
scanVars(body, n);
} else {
// It's the global block
Preconditions.checkState(scope.getParent() == null);
scanVars(n, null);
}
}
/**
* Scans and gather variables declarations under a Node
*/
private void scanVars(Node n, Node parent) {
switch (n.getType()) {
case Token.VAR:
// Declare all variables. e.g. var x = 1, y, z;
for (Node child = n.getFirstChild();
child != null;) {
Node next = child.getNext();
Preconditions.checkState(child.getType() == Token.NAME);
String name = child.getString();
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> declareVar(name, child, n, parent, null, n);
child = next;
}
return;
case Token.FUNCTION:
if (NodeUtil.isFunctionExpression(n)) {
return;
}
String fnName = n.getFirstChild().getString();
if (fnName.isEmpty()) {
// This is invalid, but allow it so the checks can catch it.
return;
}
declareVar(fnName, n.getFirstChild(), n, parent, null, n);
return; // should not examine function's children
case Token.CATCH:
Preconditions.checkState(n.getChildCount() == 2);
Preconditions.checkState(n.getFirstChild().getType() == Token.NAME);
// the first child is the catch var and the third child
// is the code block
final Node var = n.getFirstChild();
final Node block = var.getNext();
declareVar(var.getString(), var, n, parent, null, n);
scanVars(block, n);
return; // only one child to scan
case Token.SCRIPT:
sourceName = (String) n.getProp(Node.SOURCENAME_PROP);
break;
}
// Variables can only occur in statement-level nodes, so
// we only need to traverse children in a couple special cases.
if (NodeUtil.isControlStructure(n) || NodeUtil.isStatementBlock(n)) {
for (Node child = n.getFirstChild();
child != null;) {
Node next = child.getNext();
scanVars(child, n);
child = next;
}
}
}
/**
* Interface for injectable duplicate handling.
*/
interface RedeclarationHandler {
void onRedeclaration(
Scope s, String name,
Node n, Node parent, Node gramps, Node nodeWithLineNumber);
}
/**
* The default handler for duplicate declarations.
*/
private class DefaultRedeclarationHandler implements RedeclarationHandler {
public void onRedeclaration(
Scope s, String name,
Node n, Node parent, Node gramps, Node nodeWithLineNumber) {
// Don't allow multiple variables to be declared at the top level scope
if (scope.isGlobal()) {
Scope.Var origVar = scope.getVar(name);
Node origParent
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> }
}
super.add(n, context);
}
private String getTypeAnnotation(Node node) {
JSType type = node.getJSType();
if (type instanceof FunctionType) {
return getFunctionAnnotation(node);
} else if (type != null && !type.isUnknownType()
&& !type.isEmptyType() && !type.isVoidType() &&
!type.isFunctionPrototypeType()) {
return "/** @type {" + node.getJSType() + "} */\n";
} else {
return "";
}
}
/**
* @param fnNode A node for a function for which to generate a type annotation
*/
private String getFunctionAnnotation(Node fnNode) {
Preconditions.checkState(fnNode.getType() == Token.FUNCTION);
StringBuilder sb = new StringBuilder("/**\n");
JSType type = fnNode.getJSType();
if (type == null || type.isUnknownType()) {
return "";
}
FunctionType funType = (FunctionType) fnNode.getJSType();
// We need to use the child nodes of the function as the nodes for the
// parameters of the function type do not have the real parameter names.
// FUNCTION
// NAME
// LP
// NAME param1
// NAME param2
if (fnNode != null) {
Node paramNode = NodeUtil.getFnParameters(fnNode).getFirstChild();
// Param types
for (Node n : funType.getParameters()) {
// Bail out if the paramNode is not there.
if (paramNode == null) {
break;
}
sb.append(" * @param {" + getParameterNodeJSDocType(n) + "} ");
sb.append(paramNode.getString());
sb.append("\n");
paramNode = paramNode.getNext();
}
}
// Return type
JSType retType = funType.getReturnType();
if (retType != null && !retType.isUnknownType() && !retType.isEmptyType()) {
sb.append(" * @return {" + retType + "}\n");
}
// Constructor/interface
if (funType.isConstructor() || funType.isInterface()) {
FunctionType superConstructor = funType.getSuperClassConstructor();
if
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> {
this(new ContextualRenamer());
}
MakeDeclaredNamesUnique(Renamer renamer) {
this.rootRenamer = renamer;
}
static CompilerPass getContextualRenameInverter(AbstractCompiler compiler) {
return new ContextualRenameInverter(compiler);
}
@Override
public void enterScope(NodeTraversal t) {
Node declarationRoot = t.getScopeRoot();
Renamer renamer;
if (nameStack.isEmpty()) {
// If the contextual renamer is being used the starting context can not
// be a function.
Preconditions.checkState(
declarationRoot.getType() != Token.FUNCTION ||
!(rootRenamer instanceof ContextualRenamer));
Preconditions.checkState(t.inGlobalScope());
renamer = rootRenamer;
} else {
renamer = nameStack.peek().forChildScope();
}
if (declarationRoot.getType() == Token.FUNCTION) {
// Add the function parameters
Node fnParams = declarationRoot.getFirstChild().getNext();
for (Node c = fnParams.getFirstChild(); c != null; c = c.getNext()) {
String name = c.getString();
renamer.addDeclaredName(name);
}
// Add the function body declarations
Node functionBody = declarationRoot.getLastChild();
findDeclaredNames(functionBody, null, renamer);
} else {
// Add the block declarations
findDeclaredNames(declarationRoot, null, renamer);
}
nameStack.push(renamer);
}
@Override
public void exitScope(NodeTraversal t) {
if (!t.inGlobalScope()) {
nameStack.pop();
}
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
switch (n.getType()) {
case Token.FUNCTION:
{
// Add recursive function name, if needed.
// NOTE: "enterScope" is called after we need to pick up this name.
Renamer renamer = nameStack.peek().forChildScope();
// If needed, add the function recursive name.
String name = n.getFirstChild().getString();
if (name != null && !name.isEmpty() && parent != null
&& !NodeUtil.isFunctionDeclaration(n
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>)) {
renamer.addDeclaredName(name);
}
nameStack.push(renamer);
}
break;
case Token.CATCH:
{
Renamer renamer = nameStack.peek().forChildScope();
String name = n.getFirstChild().getString();
renamer.addDeclaredName(name);
nameStack.push(renamer);
}
break;
}
return true;
}
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
switch (n.getType()) {
case Token.NAME:
String newName = getReplacementName(n.getString());
if (newName != null) {
Renamer renamer = nameStack.peek();
if (renamer.stripConstIfReplaced()) {
// TODO(johnlenz): Do we need to do anything about the javadoc?
n.removeProp(Node.IS_CONSTANT_NAME);
}
n.setString(newName);
t.getCompiler().reportCodeChange();
}
break;
case Token.FUNCTION:
// Remove function recursive name (if any).
nameStack.pop();
break;
case Token.CATCH:
// Remove catch except name from the stack of names.
nameStack.pop();
break;
}
}
/**
* Walks the stack of name maps and finds the replacement name for the
* current scope.
*/
private String getReplacementName(String oldName) {
for (Renamer names : nameStack) {
String newName = names.getReplacementName(oldName);
if (newName != null) {
return newName;
}
}
return null;
}
/**
* Traverses the current scope and collects declared names. Does not
* decent into functions or add CATCH exceptions.
*/
private void findDeclaredNames(Node n, Node parent, Renamer renamer) {
// Do a shallow traversal, so don't traverse into function declarations,
// except for the name of the function itself.
if (parent == null
|| parent.getType() != Token.FUNCTION
|| n == parent.getFirstChild()) {
if (NodeUtil.isVarDeclaration(n)) {
renamer.addDeclaredName(n.getString());
} else if (Node
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>Util.isFunctionDeclaration(n)) {
Node nameNode = n.getFirstChild();
renamer.addDeclaredName(nameNode.getString());
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
findDeclaredNames(c, n, renamer);
}
}
}
/**
* Declared names renaming policy interface.
*/
interface Renamer {
/**
* Called when a declared name is found in the local current scope.
*/
void addDeclaredName(String name);
/**
* @return A replacement name, null if oldName is unknown or should not
* be replaced.
*/
String getReplacementName(String oldName);
/**
* @return Whether the constant-ness of a name should be removed.
*/
boolean stripConstIfReplaced();
/**
* @return A Renamer for a scope within the scope of the current Renamer.
*/
Renamer forChildScope();
}
/**
* Inverts the transformation by {@link ContextualRenamer}, when possible.
*/
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
private final AbstractCompiler compiler;
// The set of names referenced in the current scope.
private Set<String> referencedNames = ImmutableSet.of();
// Stack reference sets.
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
// Name are globally unique initially, so we don't need a per-scope map.
private Map<String, List<Node>> nameMap = Maps.newHashMap();
private ContextualRenameInverter(AbstractCompiler compiler) {
this.compiler = compiler;
}
public void process(Node externs, Node js) {
NodeTraversal.traverse(compiler, js, this);
}
public static String getOrginalName(String name) {
int index = indexOfSeparator(name);
return (index == -1) ? name : name.substring(0, index);
}
private static int indexOfSeparator(String name) {
return name.lastIndexOf(ContextualRenamer.UNIQUE_ID_SEPARATOR);
}
private boolean containsSeparator(String name) {
return name.indexOf(ContextualRenamer.UNIQUE_ID_SEPARATOR) != -1;
}
/**
*
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>isValidName(newName)) {
newName = original +
ContextualRenamer.UNIQUE_ID_SEPARATOR + String.valueOf(i++);
}
return newName;
}
/**
* @return Whether the name is valid to use in the local scope.
*/
private boolean isValidName(String name) {
if (TokenStream.isJSIdentifier(name) &&
!referencedNames.contains(name) &&
!name.equals(ARGUMENTS)) {
return true;
}
return false;
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
return true;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
if (t.inGlobalScope()) {
return;
}
if (NodeUtil.isReferenceName(node)) {
String name = node.getString();
// Add all referenced names to the set so it is possible to check for
// conflicts.
referencedNames.add(name);
// Store only references to candidate names in the node map.
if (containsSeparator(name)) {
addCandidateNameReference(name, node);
}
}
}
private void addCandidateNameReference(String name, Node n) {
List<Node> nodes = nameMap.get(name);
if (null == nodes) {
nodes = Lists.newLinkedList();
nameMap.put(name, nodes);
}
nodes.add(n);
}
}
/**
* Rename every locally name to be unique, the first encountered declaration
* (specifically global names) are left in their original form. Those that are
* renamed are made unique by giving them a unique suffix based on
* the number of declarations of the name.
*
* The root ContextualRenamer is assumed to be in GlobalScope.
*
* Used by the Normalize pass.
* @see Normalize
*/
static class ContextualRenamer implements Renamer {
private final Multiset<String> nameUsage;
private final Map<String, String> declarations = Maps.newHashMap();
private final boolean global;
final static String UNIQUE_ID_SEPARATOR = "$$";
ContextualRenamer() {
this.global = true;
nameUsage = HashMultiset.create();
}
/**
*
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> * possible.
*/
private void maybeCollapseIntoForStatements(Node n, Node parent) {
// Only SCRIPT, BLOCK, and LABELs can have FORs that can be collapsed into.
// LABELs are not supported here.
if (parent == null || !NodeUtil.isStatementBlock(parent)) {
return;
}
// Is the current node something that can be in a for loop initializer?
if (!NodeUtil.isExpressionNode(n) && !NodeUtil.isVar(n)) {
return;
}
// Is the next statement a valid FOR?
Node nextSibling = n.getNext();
if (nextSibling == null) {
return;
} else if (NodeUtil.isForIn(nextSibling)) {
Node forNode = nextSibling;
Node forVar = forNode.getFirstChild();
if (NodeUtil.isName(forVar)
&& NodeUtil.isVar(n) && n.hasOneChild()) {
Node name = n.getFirstChild();
if (!name.hasChildren()
&& forVar.getString().equals(name.getString())) {
// Ok, the names match, and the var declaration does not have an
// initializer. Move it into the loop.
parent.removeChild(n);
forNode.replaceChild(forVar, n);
compiler.reportCodeChange();
}
}
} else if (nextSibling.getType() == Token.FOR
&& nextSibling.getFirstChild().getType() == Token.EMPTY) {
// Does the current node contain an in operator? If so, embedding
// the expression in a for loop can cause some Javascript parsers (such
// as the Playstation 3's browser based on Access's NetFront
// browser) to fail to parse the code.
// See bug 1778863 for details.
if (NodeUtil.containsType(n, Token.IN)) {
return;
}
// Move the current node into the FOR loop initializer.
Node forNode = nextSibling;
Node oldInitializer = forNode.getFirstChild();
parent.removeChild(n);
Node newInitializer;
if (NodeUtil.isVar(n)) {
newInitializer = n;
} else {
// Extract the expression from EXPR_RESULT node.
Preconditions.checkState(n.
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>precation(NodeTraversal t, Node n, Node parent) {
// Don't bother checking definitions or constructors.
if (parent.getType() == Token.FUNCTION || parent.getType() == Token.VAR ||
parent.getType() == Token.NEW) {
return;
}
Scope.Var var = t.getScope().getVar(n.getString());
JSDocInfo docInfo = var == null ? null : var.getJSDocInfo();
if (docInfo != null && docInfo.isDeprecated() &&
shouldEmitDeprecationWarning(t, n, parent)) {
if (docInfo.getDeprecationReason() != null) {
compiler.report(
t.makeError(n, DEPRECATED_NAME_REASON, n.getString(),
docInfo.getDeprecationReason()));
} else {
compiler.report(
t.makeError(n, DEPRECATED_NAME, n.getString()));
}
}
}
/**
* Checks the given GETPROP node to ensure that access restrictions are
* obeyed.
*/
private void checkPropertyDeprecation(NodeTraversal t, Node n, Node parent) {
// Don't bother checking constructors.
if (parent.getType() == Token.NEW) {
return;
}
ObjectType objectType =
ObjectType.cast(dereference(n.getFirstChild().getJSType()));
String propertyName = n.getLastChild().getString();
if (objectType != null) {
String deprecationInfo
= getPropertyDeprecationInfo(objectType, propertyName);
if (deprecationInfo != null &&
shouldEmitDeprecationWarning(t, n, parent)) {
if (!deprecationInfo.isEmpty()) {
compiler.report(
t.makeError(n, DEPRECATED_PROP_REASON, propertyName,
validator.getReadableJSTypeName(n.getFirstChild(), true),
deprecationInfo));
} else {
compiler.report(
t.makeError(n, DEPRECATED_PROP, propertyName,
validator.getReadableJSTypeName(n.getFirstChild(), true)));
}
}
}
}
/**
* Determines whether the given name is visible in the current context.
* @param t The current traversal.
* @param name The name node.
*/
private void checkNameVisibility(NodeTraversal t, Node name, Node parent) {
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> Var var = t.getScope().getVar(name.getString());
if (var != null) {
JSDocInfo docInfo = var.getJSDocInfo();
if (docInfo != null) {
// If a name is private, make sure that we're in the same file.
Visibility visibility = docInfo.getVisibility();
if (visibility == Visibility.PRIVATE &&
!t.getInput().getName().equals(docInfo.getSourceName())) {
if (docInfo.isConstructor() &&
isValidPrivateConstructorAccess(parent)) {
return;
}
compiler.report(
t.makeError(name, BAD_PRIVATE_GLOBAL_ACCESS,
name.getString(), docInfo.getSourceName()));
}
}
}
}
/**
* Determines whether the given property is visible in the current context.
* @param t The current traversal.
* @param getprop The getprop node.
*/
private void checkPropertyVisibility(NodeTraversal t,
Node getprop, Node parent) {
ObjectType objectType =
ObjectType.cast(dereference(getprop.getFirstChild().getJSType()));
String propertyName = getprop.getLastChild().getString();
if (objectType != null) {
// Is this a normal property access, or are we trying to override
// an existing property?
boolean isOverride = t.inGlobalScope() &&
parent.getType() == Token.ASSIGN &&
parent.getFirstChild() == getprop;
// Find the lowest property defined on a class with visibility
// information.
if (isOverride) {
objectType = objectType.getImplicitPrototype();
}
JSDocInfo docInfo = null;
for (; objectType != null;
objectType = objectType.getImplicitPrototype()) {
docInfo = objectType.getOwnPropertyJSDocInfo(propertyName);
if (docInfo != null &&
docInfo.getVisibility() != Visibility.INHERITED) {
break;
}
}
if (objectType == null) {
// We couldn't find a visibility modifier; assume it's public.
return;
}
boolean sameInput =
t.getInput().getName().equals(docInfo.getSourceName());
Visibility visibility = docInfo.getVisibility();
JSType ownerType = normalizeClassType(objectType);
if (isOverride)
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>
public static String getMessage1(String messageId, Object arg1)
{
Object[] arguments = {arg1};
return getMessage(messageId, arguments);
}
public static String getMessage2(
String messageId, Object arg1, Object arg2)
{
Object[] arguments = {arg1, arg2};
return getMessage(messageId, arguments);
}
public static String getMessage3(
String messageId, Object arg1, Object arg2, Object arg3)
{
Object[] arguments = {arg1, arg2, arg3};
return getMessage(messageId, arguments);
}
public static String getMessage4(
String messageId, Object arg1, Object arg2, Object arg3, Object arg4)
{
Object[] arguments = {arg1, arg2, arg3, arg4};
return getMessage(messageId, arguments);
}
/* OPT there's a noticable delay for the first error! Maybe it'd
* make sense to use a ListResourceBundle instead of a properties
* file to avoid (synchronized) text parsing.
*/
public static String getMessage(String messageId, Object[] arguments)
{
final String defaultResource
= "rhino_ast.java.com.google.javascript.rhino.Messages";
Context cx = Context.getCurrentContext();
Locale locale = cx != null ? cx.getLocale() : Locale.getDefault();
// ResourceBundle does cacheing.
ResourceBundle rb = ResourceBundle.getBundle(defaultResource, locale);
String formatString;
try {
formatString = rb.getString(messageId);
} catch (java.util.MissingResourceException mre) {
throw new RuntimeException
("no message resource found for message property "+ messageId);
}
/*
* It's OK to format the string, even if 'arguments' is null;
* we need to format it anyway, to make double ''s collapse to
* single 's.
*/
// TODO: MessageFormat is not available on pJava
MessageFormat formatter = new MessageFormat(formatString);
return formatter.format(arguments);
}
public static EcmaError constructError(String error, String message)
{
int[] linep = new int[1];
String filename = Context.getSourcePositionFromStack(linep);
return constructError(error, message, filename, line
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> lineno, int charno) {
errorReporter.warning(ScriptRuntime.getMessage0(messageId),
sourceName, lineno, null, charno);
}
}
// The DocInfo with the fileoverview tag for the whole file.
private JSDocInfo fileOverviewJSDocInfo = null;
private State state;
private final Map<String, Annotation> annotationNames;
private final Set<String> suppressionNames;
private Node.FileLevelJsDocBuilder fileLevelJsDocBuilder;
/**
* Sets the JsDocBuilder for the file-level (root) node of this parse. The
* parser uses the builder to append any preserve annotations it encounters
* in jsdoc comments.
*
* @param fileLevelJsDocBuilder
*/
void setFileLevelJsDocBuilder(
Node.FileLevelJsDocBuilder fileLevelJsDocBuilder) {
this.fileLevelJsDocBuilder = fileLevelJsDocBuilder;
}
/**
* Sets the file overview JSDocInfo, in order to warn about multiple uses of
* the @fileoverview tag in a file.
*/
void setFileOverviewJSDocInfo(JSDocInfo fileOverviewJSDocInfo) {
this.fileOverviewJSDocInfo = fileOverviewJSDocInfo;
}
private enum State {
SEARCHING_ANNOTATION,
SEARCHING_NEWLINE,
NEXT_IS_ANNOTATION
}
JsDocInfoParser(JsDocTokenStream stream,
String sourceName,
Config config,
ErrorReporter errorReporter) {
this.stream = stream;
this.sourceName = sourceName;
this.jsdocBuilder = new JSDocInfoBuilder(config.parseJsDocDocumentation);
this.annotationNames = config.annotationNames;
this.suppressionNames = config.suppressionNames;
this.errorReporter = errorReporter;
}
/**
* Parses a string containing a JsDoc type declaration, returning the
* type if the parsing succeeded or {@code null} if it failed.
*/
public static Node parseTypeString(String typeString) {
Config config = new Config(
Sets.<String>newHashSet(),
Sets.<String>newHashSet(),
false);
JsDocInfoParser parser = new JsDocInfoParser(
new JsDocTokenStream(typeString),
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> "typeparsing",
config,
NullErrorReporter.forNewRhino());
return parser.parseTopLevelTypeExpression(parser.next());
}
/**
* Parses a {@link JSDocInfo} object. This parsing method reads all tokens
* returned by the {@link JsDocTokenStream#getJsDocToken()} method until the
* {@link JsDocToken#EOC} is returned.
*
* @return {@code true} if JSDoc information was correctly parsed,
* {@code false} otherwise
*/
boolean parse() {
int lineno;
int charno;
// JSTypes are represented as Rhino AST nodes, and then resolved later.
JSTypeExpression type;
state = State.SEARCHING_ANNOTATION;
skipEOLs();
JsDocToken token = next();
// Always record that we have a comment.
if (jsdocBuilder.shouldParseDocumentation()) {
ExtractionInfo blockInfo = extractBlockComment(token);
token = blockInfo.token;
if (!blockInfo.string.isEmpty()) {
jsdocBuilder.recordBlockDescription(blockInfo.string);
}
} else {
if (token != JsDocToken.ANNOTATION &&
token != JsDocToken.EOC) {
// Mark that there was a description, but don't bother marking
// what it was.
jsdocBuilder.recordBlockDescription("");
}
}
// Parse the actual JsDoc.
retry: for (;;) {
switch (token) {
case ANNOTATION:
if (state == State.SEARCHING_ANNOTATION) {
state = State.SEARCHING_NEWLINE;
lineno = stream.getLineno();
charno = stream.getCharno();
String annotationName = stream.getString();
Annotation annotation = annotationNames.get(annotationName);
if (annotation == null) {
parser.addWarning("msg.bad.jsdoc.tag", annotationName,
stream.getLineno(), stream.getCharno());
} else {
// Mark the beginning of the annotation.
jsdocBuilder.markAnnotation(annotationName, lineno, charno);
switch (annotation) {
case AUTHOR:
if (jsdocBuilder.shouldParseDocumentation()) {
ExtractionInfo authorInfo = extractSingleLineBlock();
String author =
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> = stream.getCharno();
type = null;
if (token == JsDocToken.LC) {
type = createJSTypeExpression(
parseAndRecordTypeNode(token));
if (type == null) {
// parsing error reported during recursive descent
// recovering parsing
token = eatTokensUntilEOL();
continue retry;
}
}
// *Update* the token to that after the type annotation.
token = current();
// Save the throw type.
jsdocBuilder.recordThrowType(type);
// Find the throw's description (if applicable).
if (jsdocBuilder.shouldParseDocumentation()) {
ExtractionInfo descriptionInfo =
extractMultilineTextualBlock(token);
String description = descriptionInfo.string;
if (description.length() > 0) {
jsdocBuilder.recordThrowDescription(type, description);
}
token = descriptionInfo.token;
} else {
token = eatTokensUntilEOL(token);
}
continue retry;
case PARAM:
skipEOLs();
token = next();
lineno = stream.getLineno();
charno = stream.getCharno();
type = null;
if (token == JsDocToken.LC) {
type = createJSTypeExpression(
parseAndRecordParamTypeNode(token));
if (type == null) {
// parsing error reported during recursive descent
// recovering parsing
token = eatTokensUntilEOL();
continue retry;
}
skipEOLs();
token = next();
lineno = stream.getLineno();
charno = stream.getCharno();
}
String name = null;
boolean isBracketedParam = JsDocToken.LB == token;
if (isBracketedParam) {
token = next();
}
if (JsDocToken.STRING != token) {
parser.addWarning("msg.missing.variable.name",
lineno, charno);
} else {
name = stream.getString();
if (isBracketedParam) {
token = next();
// Throw out JsDocToolkit's "default" parameter annotation.
// It makes no sense under our type system.
if (JsDocToken.EQUALS == token) {
token = next();
if (JsDocToken.STRING == token) {
token = next();
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> templateTypeName)) {
parser.addWarning("msg.jsdoc.template.at.most.once",
stream.getLineno(), stream.getCharno());
}
token = templateInfo.token;
continue retry;
case VERSION:
ExtractionInfo versionInfo = extractSingleLineBlock();
String version = versionInfo.string;
if (version.length() == 0) {
parser.addWarning("msg.jsdoc.versionmissing",
stream.getLineno(), stream.getCharno());
} else {
if (!jsdocBuilder.recordVersion(version)) {
parser.addWarning("msg.jsdoc.extraversion",
stream.getLineno(), stream.getCharno());
}
}
token = versionInfo.token;
continue retry;
case DEFINE:
case RETURN:
case THIS:
case TYPE:
case TYPEDEF:
skipEOLs();
lineno = stream.getLineno();
charno = stream.getCharno();
token = next();
Node typeNode = parseAndRecordTypeNode(token, lineno, charno);
if (annotation == Annotation.THIS) {
typeNode = wrapNode(Token.BANG, typeNode);
if (typeNode != null && token != JsDocToken.LC) {
typeNode.putBooleanProp(Node.BRACELESS_TYPE, true);
}
}
type = createJSTypeExpression(typeNode);
if (type == null) {
// error reported during recursive descent
// recovering parsing
} else {
switch (annotation) {
case DEFINE:
if (!jsdocBuilder.recordDefineType(type)) {
parser.addWarning("msg.jsdoc.define",
lineno, charno);
}
break;
case RETURN:
if (!jsdocBuilder.recordReturnType(type)) {
parser.addWarning(
"msg.jsdoc.incompat.type", lineno, charno);
break;
}
// *Update* the token to that after the type annotation.
token = current();
// Find the return's description (if applicable).
if (jsdocBuilder.shouldParseDocumentation()) {
ExtractionInfo returnDescriptionInfo =
extractMultilineTextualBlock(token);
String returnDescription =
returnDescriptionInfo.string;
if (
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> = new HashSet<String>();
while (true) {
if (match(JsDocToken.STRING)) {
String name = stream.getString();
if (!suppressionNames.contains(name)) {
parser.addWarning("msg.jsdoc.suppress.unknown", name,
stream.getLineno(), stream.getCharno());
}
suppressions.add(stream.getString());
token = next();
} else {
parser.addWarning("msg.jsdoc.suppress",
stream.getLineno(), stream.getCharno());
return token;
}
if (match(JsDocToken.PIPE)) {
token = next();
} else {
break;
}
}
if (!match(JsDocToken.RC)) {
parser.addWarning("msg.jsdoc.suppress",
stream.getLineno(), stream.getCharno());
} else {
token = next();
if (!jsdocBuilder.recordSuppressions(suppressions)) {
parser.addWarning("msg.jsdoc.suppress.duplicate",
stream.getLineno(), stream.getCharno());
}
}
}
return token;
}
/**
* Looks for a type expression at the current token and if found,
* returns it. Note that this method consumes input.
*
* @param token The current token.
* @return The type expression found or null if none.
*/
private Node parseAndRecordTypeNode(JsDocToken token) {
return parseAndRecordTypeNode(token, token == JsDocToken.LC);
}
/**
* Looks for a type expression at the current token and if found,
* returns it. Note that this method consumes input.
*
* @param token The current token.
* @param matchingLC Whether the type expression starts with a "{".
* @return The type expression found or null if none.
*/
private Node parseAndRecordTypeNode(JsDocToken token, boolean matchingLC) {
return parseAndRecordTypeNode(token, stream.getLineno(), stream.getCharno(),
matchingLC, false);
}
/**
* Looks for a type expression at the current token and if found,
* returns it. Note that this method consumes input.
*
* @param token The current token.
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> The current token.
* @param lineno The line of the type expression.
* @param startCharno The starting character position of the type expression.
* @param matchingLC Whether the type expression starts with a "{".
* @param onlyParseSimpleNames If true, only simple type names are parsed
* (via a call to parseTypeNameAnnotation instead of
* parseTypeExpressionAnnotation).
* @return The type expression found or null if none.
*/
private Node parseAndRecordTypeNode(JsDocToken token, int lineno,
int startCharno,
boolean matchingLC,
boolean onlyParseSimpleNames) {
Node typeNode = null;
if (onlyParseSimpleNames) {
typeNode = parseTypeNameAnnotation(token);
} else {
typeNode = parseTypeExpressionAnnotation(token);
}
if (typeNode != null && !matchingLC) {
typeNode.putBooleanProp(Node.BRACELESS_TYPE, true);
}
int endCharno = stream.getCharno();
jsdocBuilder.markTypeNode(typeNode, lineno, startCharno, endCharno,
matchingLC);
return typeNode;
}
/**
* Converts a JSDoc token to its string representation.
*/
private String toString(JsDocToken token) {
switch (token) {
case ANNOTATION:
return "@" + stream.getString();
case BANG:
return "!";
case COMMA:
return ",";
case COLON:
return ":";
case GT:
return ">";
case LB:
return "[";
case LC:
return "{";
case LP:
return "(";
case LT:
return ".<";
case QMARK:
return "?";
case PIPE:
return "|";
case RB:
return "]";
case RC:
return "}";
case RP:
return ")";
case STAR:
return "*";
case ELLIPSIS:
return "...";
case EQUALS:
return "=";
case STRING:
return stream.getString();
default:
throw new IllegalStateException(token.toString());
}
}
/**
* Constructs a new {@code JSTypeExpression}.
* @param n A node. May be null.
*/
private JSTypeExpression createJSTypeExpression(Node n) {
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>
return wrapNode(Token.BANG, basicTypeExpr);
}
}
return basicTypeExpr;
}
}
/**
* BasicTypeExpression := '*' | 'null' | 'undefined' | TypeName
* | FunctionType | UnionType | RecordType | ArrayType
*/
private Node parseBasicTypeExpression(JsDocToken token) {
if (token == JsDocToken.STAR) {
return newNode(Token.STAR);
} else if (token == JsDocToken.LB) {
skipEOLs();
return parseArrayType(next());
} else if (token == JsDocToken.LC) {
skipEOLs();
return parseRecordType(next());
} else if (token == JsDocToken.LP) {
skipEOLs();
return parseUnionType(next());
} else if (token == JsDocToken.STRING) {
String string = stream.getString();
if ("function".equals(string)) {
skipEOLs();
return parseFunctionType(next());
} else if ("null".equals(string) || "undefined".equals(string)) {
return newStringNode(string);
} else {
return parseTypeName(token);
}
}
return reportGenericTypeSyntaxWarning();
}
/**
* TypeName := NameExpression | NameExpression TypeApplication
* TypeApplication := '.<' TypeExpressionList '>'
* TypeExpressionList := TypeExpression // a white lie
*/
private Node parseTypeName(JsDocToken token) {
if (token != JsDocToken.STRING) {
return reportGenericTypeSyntaxWarning();
}
Node typeName = newStringNode(stream.getString());
if (match(JsDocToken.LT)) {
next();
skipEOLs();
Node memberType = parseTypeExpressionList(next());
if (memberType != null) {
typeName.addChildToFront(memberType);
skipEOLs();
if (!match(JsDocToken.GT)) {
return reportTypeSyntaxWarning("msg.jsdoc.missing.gt");
}
next();
}
}
return typeName;
}
/**
* FunctionType := 'function' FunctionSignatureType
* FunctionSignatureType :=
* TypeParameters '(' 'this' ':' TypeName, ParametersType ')' ResultType
*/
private Node parseFunctionType(JsDocToken token)
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> {
// NOTE(nicksantos): We're not implementing generics at the moment, so
// just throw out TypeParameters.
if (token != JsDocToken.LP) {
return reportTypeSyntaxWarning("msg.jsdoc.missing.lp");
}
Node functionType = newNode(Token.FUNCTION);
Node parameters = null;
skipEOLs();
if (!match(JsDocToken.RP)) {
token = next();
boolean hasParams = true;
if (token == JsDocToken.STRING && "this".equals(stream.getString())) {
if (match(JsDocToken.COLON)) {
next();
skipEOLs();
Node thisType = wrapNode(Token.THIS, parseTypeName(next()));
if (thisType == null) {
return null;
}
functionType.addChildToFront(thisType);
} else {
return reportTypeSyntaxWarning("msg.jsdoc.missing.colon");
}
if (match(JsDocToken.COMMA)) {
next();
skipEOLs();
token = next();
} else {
hasParams = false;
}
}
if (hasParams) {
parameters = parseParametersType(token);
if (parameters == null) {
return null;
}
}
}
if (parameters != null) {
functionType.addChildToBack(parameters);
}
skipEOLs();
if (!match(JsDocToken.RP)) {
return reportTypeSyntaxWarning("msg.jsdoc.missing.rp");
}
skipEOLs();
Node resultType = parseResultType(next());
if (resultType == null) {
return null;
} else {
functionType.addChildToBack(resultType);
}
return functionType;
}
/**
* ParametersType := RestParameterType | NonRestParametersType
* | NonRestParametersType ',' RestParameterType
* RestParameterType := '...' Identifier
* NonRestParametersType := ParameterType ',' NonRestParametersType
* | ParameterType
* | OptionalParametersType
* OptionalParametersType := OptionalParameterType
* | OptionalParameterType, OptionalParametersType
* OptionalParameterType := ParameterType=
* ParameterType := TypeExpression | Identifier ':' TypeExpression
*/
// NOTE(nicksantos): The official ES4 grammar forces optional
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>
break;
}
} while (match(JsDocToken.COMMA));
}
if (isVarArgs && match(JsDocToken.COMMA)) {
return reportTypeSyntaxWarning("msg.jsdoc.function.varargs");
}
// The right paren will be checked by parseFunctionType
return paramsType;
}
/**
* ResultType := <empty> | ':' void | ':' TypeExpression
*/
private Node parseResultType(JsDocToken token) {
skipEOLs();
if (!match(JsDocToken.COLON)) {
return newNode(Token.EMPTY);
}
token = next();
skipEOLs();
if (match(JsDocToken.STRING) && "void".equals(stream.getString())) {
next();
return newNode(Token.VOID);
} else {
return parseTypeExpression(next());
}
}
/**
* UnionType := '(' TypeUnionList ')'
* TypeUnionList := TypeExpression | TypeExpression '|' TypeUnionList
*
* We've removed the empty union type.
*/
private Node parseUnionType(JsDocToken token) {
return parseUnionTypeWithAlternate(token, null);
}
/**
* Create a new union type, with an alternate that has already been
* parsed. The alternate may be null.
*/
private Node parseUnionTypeWithAlternate(JsDocToken token, Node alternate) {
Node union = newNode(Token.PIPE);
if (alternate != null) {
union.addChildToBack(alternate);
}
Node expr = null;
do {
if (expr != null) {
skipEOLs();
token = next();
Preconditions.checkState(
token == JsDocToken.PIPE || token == JsDocToken.COMMA);
boolean isPipe = token == JsDocToken.PIPE;
if (isPipe && match(JsDocToken.PIPE)) {
// We support double pipes for backwards compatiblity.
next();
}
skipEOLs();
token = next();
}
expr = parseTypeExpression(token);
if (expr == null) {
return null;
}
union.addChildToBack(expr);
// We support commas for backwards compatiblity.
} while (match(JsDocToken.PIPE, JsDocToken.COMMA));
if
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>(JsDocToken.COMMA)) {
break;
}
// Move to the comma token.
next();
// Move to the token passed the comma.
skipEOLs();
token = next();
} while (true);
return fieldTypeList;
}
/**
* FieldType := FieldName | FieldName ':' TypeExpression
*/
private Node parseFieldType(JsDocToken token) {
Node fieldName = parseFieldName(token);
if (fieldName == null) {
return null;
}
skipEOLs();
if (!match(JsDocToken.COLON)) {
return fieldName;
}
// Move to the colon.
next();
// Move to the token after the colon and parse
// the type expression.
skipEOLs();
Node typeExpression = parseTypeExpression(next());
if (typeExpression == null) {
return null;
}
Node fieldType = newNode(Token.COLON);
fieldType.addChildToBack(fieldName);
fieldType.addChildToBack(typeExpression);
return fieldType;
}
/**
* FieldName := NameExpression | StringLiteral | NumberLiteral |
* ReservedIdentifier
*/
private Node parseFieldName(JsDocToken token) {
switch (token) {
case STRING:
String string = stream.getString();
return newStringNode(string);
default:
return null;
}
}
private Node wrapNode(int type, Node n) {
return n == null ? null :
new Node(type, n, stream.getLineno(), stream.getCharno());
}
private Node newNode(int type) {
return new Node(type, stream.getLineno(), stream.getCharno());
}
private Node newStringNode(String s) {
return Node.newString(s, stream.getLineno(), stream.getCharno());
}
private Node reportTypeSyntaxWarning(String warning) {
parser.addWarning(warning, stream.getLineno(), stream.getCharno());
return null;
}
private Node reportGenericTypeSyntaxWarning() {
return reportTypeSyntaxWarning("msg.jsdoc.type.syntax");
}
/**
* Eats tokens until {@link JsDocToken#EOL} included, and switches back the
* state to {@link State#SEARCHING_ANNOTATION}.
*/
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>Graph<Node> cfg = t.getControlFlowGraph();
LiveVariablesAnalysis liveness =
new LiveVariablesAnalysis(cfg, scope, compiler);
// If the function has exactly 2 params, mark them as escaped. This is
// a work-around for an IE bug where it throws an exception if you
// write to the parameters of the callback in a sort(). See:
// http://code.google.com/p/closure-compiler/issues/detail?id=58
if (scope.getRootNode().getFirstChild().getNext().getChildCount() == 2) {
liveness.markAllParametersEscaped();
}
liveness.analyze();
UndiGraph<Var, Void> interferenceGraph =
computeVariableNamesInterferenceGraph(
t, cfg, liveness.getEscapedLocals());
GraphColoring<Var, Void> coloring =
new GreedyGraphColoring<Var, Void>(interferenceGraph,
coloringTieBreaker);
coloring.color();
colorings.push(coloring);
}
@Override
public void exitScope(NodeTraversal t) {
if (t.inGlobalScope()) {
return;
}
colorings.pop();
}
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
if (colorings.isEmpty() || !NodeUtil.isName(n) ||
NodeUtil.isFunction(parent)) {
// Don't rename named functions.
return;
}
Var var = t.getScope().getVar(n.getString());
GraphNode<Var, ?> vNode = colorings.peek().getGraph().getNode(var);
if (vNode == null) {
// This is not a local.
return;
}
Var coalescedVar = colorings.peek().getPartitionSuperNode(var);
if (!usePseudoNames) {
if (vNode.getValue().equals(coalescedVar)) {
// The coalesced name is itself, nothing to do.
return;
}
// Rename.
n.setString(coalescedVar.name);
compiler.reportCodeChange();
if (NodeUtil.isVar(parent)) {
removeVarDeclaration(n);
}
} else {
// This
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> isReadFrom(use, n))) {
crossed = true;
}
}
private static boolean isAssignTo(Var var, Node n, Node parent) {
if (NodeUtil.isName(n) && var.getName().equals(n.getString()) &&
parent != null) {
if (parent.getType() == Token.LP) {
// In a function declaration, the formal parameters are assigned.
return true;
} else if (NodeUtil.isVar(parent)) {
// If this is a VAR declaration, if the name node has a child, we are
// assigning to that name.
return n.hasChildren();
}
return false; // Definitely a read.
} else {
// Lastly, any assignmentOP is also an assign.
Node name = n.getFirstChild();
return name != null && NodeUtil.isName(name) &&
var.getName().equals(name.getString()) &&
NodeUtil.isAssignmentOp(n);
}
}
private static boolean isReadFrom(Var var, Node name) {
return name != null && NodeUtil.isName(name) &&
var.getName().equals(name.getString()) &&
!NodeUtil.isLhs(name, name.getParent());
}
}
}
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> n) {
isSet = true;
type = getValueType(n.getNext());
}
break;
case Token.GETPROP:
return;
case Token.FUNCTION:
Node gramps = parent.getParent();
if (gramps == null ||
NodeUtil.isFunctionExpression(parent)) return;
isSet = true;
type = Name.Type.FUNCTION;
break;
}
}
name = n.getString();
break;
case Token.GETPROP:
// This may be a namespaced name get or set.
if (parent != null) {
switch (parent.getType()) {
case Token.ASSIGN:
if (parent.getFirstChild() == n) {
isSet = true;
type = getValueType(n.getNext());
isPropAssign = true;
}
break;
case Token.GETPROP:
return;
}
}
name = n.getQualifiedName();
if (name == null) return;
break;
default:
return;
}
// We are only interested in global names.
Scope scope = t.getScope();
if (!isGlobalNameReference(name, scope)) {
return;
}
if (isSet) {
if (isGlobalScope(scope)) {
handleSetFromGlobal(t, n, parent, name, isPropAssign, type);
} else {
handleSetFromLocal(t, n, parent, name);
}
} else {
handleGet(t, n, parent, name);
}
}
/**
* Gets the fully qualified name corresponding to an object literal key,
* as long as it and its prefix property names are valid JavaScript
* identifiers. The object literal may be nested inside of other object
* literals.
*
* For example, if called with node {@code n} representing "z" in any of
* the following expressions, the result would be "w.x.y.z":
* <code> var w = {x: {y: {z: 0}}}; </code>
* <code> w.x = {y: {z: 0}}; </code>
* <code> w.x.y = {'a': 0, 'z': 0}; </code>
*
* @param n A child of an OBJL
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>IT node
* @return The global name, or null if {@code n} doesn't correspond to the
* key of an object literal that can be named
*/
String getNameForObjLitKey(Node n) {
// Verify that this node is a key in the object literal (odd numbered).
Node parent = n.getParent();
for (Node walker = parent.getFirstChild(); walker != n;
walker = walker.getNext().getNext()) {
if (walker == null) {
return null;
}
}
Node gramps = parent.getParent();
if (gramps == null) {
return null;
}
String name;
switch (gramps.getType()) {
case Token.NAME:
// VAR
// NAME (gramps)
// OBJLIT (parent)
// STRING (n)
Node greatGramps = gramps.getParent();
if (greatGramps == null ||
greatGramps.getType() != Token.VAR) {
return null;
}
name = gramps.getString();
break;
case Token.ASSIGN:
// ASSIGN (gramps)
// NAME|GETPROP
// OBJLIT (parent)
// STRING (n)
Node lvalue = gramps.getFirstChild();
name = lvalue.getQualifiedName();
break;
case Token.OBJECTLIT:
// OBJLIT (gramps)
// STRING
// OBJLIT (parent)
// STRING (n)
Node key = gramps.getChildBefore(parent);
if (key.getType() == Token.STRING) {
name = getNameForObjLitKey(key);
} else {
return null;
}
break;
default:
return null;
}
if (name != null) {
String key = n.getString();
if (TokenStream.isJSIdentifier(key)) {
return name + '.' + key;
}
}
return null;
}
/**
* Gets the type of a value or simple expression.
*
* @param n An rvalue in an assignment or variable declaration (not null)
* @return A {@link Name.Type}
*/
Name.Type getValueType(Node n
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>g. var a = a ? a : {}).
type = determineGetTypeForHookOrBooleanExpr(t, parent, name);
}
break;
default:
type = Ref.Type.ALIASING_GET;
break;
}
}
handleGet(t, n, parent, name, type);
}
/**
* Determines whether the result of a hook (x?y:z) or boolean expression
* (x||y) or (x&&y) is assigned to a specific global name.
*
* @param t The traversal
* @param parent The parent of the current node in the traversal. This node
* should already be known to be a HOOK, AND, or OR node.
* @param name A name that is already known to be global in the current
* scope (e.g. "a" or "a.b.c.d")
* @return The expression's get type, either {@link Ref.Type#DIRECT_GET} or
* {@link Ref.Type#ALIASING_GET}
*/
Ref.Type determineGetTypeForHookOrBooleanExpr(
NodeTraversal t, Node parent, String name) {
Node prev = parent;
for (Node anc : parent.getAncestors()) {
switch (anc.getType()) {
case Token.EXPR_RESULT:
case Token.VAR:
case Token.IF:
case Token.WHILE:
case Token.FOR:
case Token.TYPEOF:
case Token.VOID:
case Token.NOT:
case Token.BITNOT:
case Token.POS:
case Token.NEG:
return Ref.Type.DIRECT_GET;
case Token.HOOK:
if (anc.getFirstChild() == prev) {
return Ref.Type.DIRECT_GET;
}
break;
case Token.ASSIGN:
if (!name.equals(anc.getFirstChild().getQualifiedName())) {
return Ref.Type.ALIASING_GET;
}
break;
case Token.NAME: // a variable declaration
if (!name.equals(anc.getString())) {
return Ref.Type.ALIASING_GET;
}
break;
case Token.CALL:
if (anc.getFirstChild() != prev) {
return Ref.Type.ALIASING_GET;
}
break
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> public void exitScope(NodeTraversal t) {
if (t.getScopeDepth() == 2) {
aliases.clear();
}
}
@Override
public final boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
if (n.getType() == Token.FUNCTION && t.inGlobalScope()) {
// Do not traverse in to functions except for goog.scope functions.
if (parent == null || !isCallToScopeMethod(parent)) {
return false;
}
}
return true;
}
private void report(NodeTraversal t, Node n, DiagnosticType error,
String... arguments) {
compiler.report(t.makeError(n, error, arguments));
hasErrors = true;
}
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
if (isCallToScopeMethod(n)) {
if (!NodeUtil.isExpressionNode(parent)) {
report(t, n, GOOG_SCOPE_USED_IMPROPERLY);
}
if (n.getChildCount() != 2) {
// The goog.scope call should have exactly 1 parameter. The first
// child is the "goog.scope" and the second should be the parameter.
report(t, n, GOOG_SCOPE_HAS_BAD_PARAMETERS);
} else {
Node anonymousFnNode = n.getChildAtIndex(1);
if (!NodeUtil.isFunction(anonymousFnNode) ||
NodeUtil.getFunctionName(anonymousFnNode) != null ||
NodeUtil.getFnParameters(anonymousFnNode).hasChildren()) {
report(t, anonymousFnNode, GOOG_SCOPE_HAS_BAD_PARAMETERS);
} else {
scopeCalls.add(n);
}
}
}
if (t.getScopeDepth() == 2) {
int type = n.getType();
if (type == Token.NAME && parent.getType() == Token.VAR) {
if (n.hasChildren() && n.getFirstChild().isQualifiedName()) {
aliases.put(n.getString(), t.getScope().getVar(n.getString()));
aliasDefinitions.add(n);
// If we found an alias, we are done.
return;
} else {
// TODO(robbyw):
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> Support using locals for private variables.
report(t, n, GOOG_SCOPE_NON_ALIAS_LOCAL, n.getString());
}
}
if (type == Token.NAME && NodeUtil.isAssignmentOp(parent) &&
n == parent.getFirstChild()) {
report(t, n, GOOG_SCOPE_ALIAS_REDEFINED, n.getString());
}
if (type == Token.RETURN) {
report(t, n, GOOG_SCOPE_USES_RETURN);
} else if (type == Token.THIS) {
report(t, n, GOOG_SCOPE_REFERENCES_THIS);
} else if (type == Token.THROW) {
report(t, n, GOOG_SCOPE_USES_THROW);
}
}
if (t.getScopeDepth() >= 2) {
if (n.getType() == Token.NAME) {
String name = n.getString();
Var aliasVar = aliases.get(name);
// Check if this name points to an alias.
if (aliasVar != null &&
t.getScope().getVar(name) == aliasVar) {
// Note, to support the transitive case, it's important we don't
// clone aliasedNode here. For example,
// var g = goog; var d = g.dom; d.createElement('DIV');
// The node in aliasedNode (which is "g") will be replaced in the
// changes pass above with "goog". If we cloned here, we'd end up
// with <code>g.dom.createElement('DIV')</code>.
Node aliasedNode = aliasVar.getInitialValue();
aliasUsages.add(new AliasedNode(n, aliasedNode));
}
}
JSDocInfo info = n.getJSDocInfo();
if (info != null) {
for (Node node : info.getTypeNodes()) {
fixTypeNode(node);
}
}
// TODO(robbyw): Error for goog.scope not at root.
}
}
private void fixTypeNode(Node typeNode) {
if (typeNode.getType() == Token.STRING) {
String name = typeNode.getString();
int endIndex = name.indexOf('.');
if (endIndex == -
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> value of a node that represents a expression. This method
* effectively emulates the <code>Boolean()</code> JavaScript cast function.
* Note: unlike getBooleanValue this function does not return UNKNOWN
* for expressions with side-effects.
*/
static TernaryValue getExpressionBooleanValue(Node n) {
switch (n.getType()) {
case Token.ASSIGN:
case Token.COMMA:
// For ASSIGN and COMMA the value is the value of the RHS.
return getExpressionBooleanValue(n.getLastChild());
case Token.NOT:
TernaryValue value = getExpressionBooleanValue(n.getLastChild());
return value.not();
case Token.AND: {
TernaryValue lhs = getExpressionBooleanValue(n.getFirstChild());
TernaryValue rhs = getExpressionBooleanValue(n.getLastChild());
return lhs.and(rhs);
}
case Token.OR: {
TernaryValue lhs = getExpressionBooleanValue(n.getFirstChild());
TernaryValue rhs = getExpressionBooleanValue(n.getLastChild());
return lhs.or(rhs);
}
case Token.HOOK: {
TernaryValue trueValue = getExpressionBooleanValue(
n.getFirstChild().getNext());
TernaryValue falseValue = getExpressionBooleanValue(n.getLastChild());
if (trueValue.equals(falseValue)) {
return trueValue;
} else {
return TernaryValue.UNKNOWN;
}
}
default:
return getBooleanValue(n);
}
}
/**
* Gets the boolean value of a node that represents a literal. This method
* effectively emulates the <code>Boolean()</code> JavaScript cast function.
*/
static TernaryValue getBooleanValue(Node n) {
switch (n.getType()) {
case Token.STRING:
return TernaryValue.forBoolean(n.getString().length() > 0);
case Token.NUMBER:
return TernaryValue.forBoolean(n.getDouble() != 0);
case Token.NULL:
case Token.FALSE:
case Token.VOID:
return TernaryValue.FALSE;
case Token.NAME:
String name = n.getString();
if ("undefined".equals(name)
|| "NaN".equals(name)) {
// We assume here that programs
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> don't change the value of the keyword
// undefined to something other than the value undefined.
return TernaryValue.FALSE;
} else if ("Infinity".equals(name)) {
return TernaryValue.TRUE;
}
break;
case Token.TRUE:
case Token.ARRAYLIT:
case Token.OBJECTLIT:
case Token.REGEXP:
return TernaryValue.TRUE;
}
return TernaryValue.UNKNOWN;
}
/**
* Gets the value of a node as a String, or null if it cannot be converted.
* When it returns a non-null String, this method effectively emulates the
* <code>String()</code> JavaScript cast function.
*/
static String getStringValue(Node n) {
// TODO(user): Convert constant array, object, and regex literals as well.
switch (n.getType()) {
case Token.NAME:
case Token.STRING:
return n.getString();
case Token.NUMBER:
double value = n.getDouble();
long longValue = (long) value;
// Return "1" instead of "1.0"
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(n.getDouble());
}
case Token.FALSE:
case Token.TRUE:
case Token.NULL:
return Node.tokenToName(n.getType());
case Token.VOID:
return "undefined";
}
return null;
}
/**
* Gets the function's name. This method recognizes five forms:
* <ul>
* <li>{@code function name() ...}</li>
* <li>{@code var name = function() ...}</li>
* <li>{@code qualified.name = function() ...}</li>
* <li>{@code var name2 = function name1() ...}</li>
* <li>{@code qualified.name2 = function name1() ...}</li>
* </ul>
* In two last cases with named function expressions, the second name is
* returned (the variable of qualified name).
*
* @param n a node whose type is {@link Token#FUNCTION}
* @return the function's name, or {@code null} if it has no name
*/
static String getFunctionName(Node n) {
Node
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> parent = n.getParent();
String name = n.getFirstChild().getString();
switch (parent.getType()) {
case Token.NAME:
// var name = function() ...
// var name2 = function name1() ...
return parent.getString();
case Token.ASSIGN:
// qualified.name = function() ...
// qualified.name2 = function name1() ...
return parent.getFirstChild().getQualifiedName();
default:
// function name() ...
return name != null && name.length() != 0 ? name : null;
}
}
/**
* Returns true if this is an immutable value.
*/
static boolean isImmutableValue(Node n) {
switch (n.getType()) {
case Token.STRING:
case Token.NUMBER:
case Token.NULL:
case Token.TRUE:
case Token.FALSE:
return true;
case Token.VOID:
case Token.NEG:
return isImmutableValue(n.getFirstChild());
case Token.NAME:
String name = n.getString();
// We assume here that programs don't change the value of the keyword
// undefined to something other than the value undefined.
return "undefined".equals(name)
|| "Infinity".equals(name)
|| "NaN".equals(name);
}
return false;
}
/**
* Returns true if this is a literal value. We define a literal value
* as any node that evaluates to the same thing regardless of when or
* where it is evaluated. So /xyz/ and [3, 5] are literals, but
* the name a is not.
*
* Function literals do not meet this definition, because they
* lexically capture variables. For example, if you have
* <code>
* function() { return a; }
* </code>
* If it is evaluated in a different scope, then it
* captures a different variable. Even if the function did not read
* any captured vairables directly, it would still fail this definition,
* because it affects the lifecycle of variables in the enclosing scope.
*
* However, a function literal with respect to a particular scope is
* a literal.
*
* @param includeFunctions If true, all function expressions will be
* treated as literals.
*/
static boolean isLiteralValue
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>
}
return true;
default:
if (isSimpleOperatorType(n.getType())) {
break;
}
if (isAssignmentOp(n)) {
// Assignments will have side effects if
// a) The RHS has side effects, or
// b) The LHS has side effects, or
// c) A name on the LHS will exist beyond the life of this statement.
if (checkForStateChangeHelper(
n.getFirstChild(), checkForNewObjects, compiler) ||
checkForStateChangeHelper(
n.getLastChild(), checkForNewObjects, compiler)) {
return true;
}
Node current = n.getFirstChild();
for (;
current.getType() == Token.GETPROP ||
current.getType() == Token.GETELEM;
current = current.getFirstChild()) { }
return !isLiteralValue(current, true);
}
return true;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (checkForStateChangeHelper(c, checkForNewObjects, compiler)) {
return true;
}
}
return false;
}
/**
* Do calls to this constructor have side effects?
*
* @param callNode - construtor call node
*/
static boolean constructorCallHasSideEffects(Node callNode) {
return constructorCallHasSideEffects(callNode, null);
}
static boolean constructorCallHasSideEffects(
Node callNode, AbstractCompiler compiler) {
Preconditions.checkArgument(
callNode.getType() == Token.NEW,
"Expected NEW node, got " + Token.name(callNode.getType()));
if (callNode.isNoSideEffectsCall()) {
return false;
}
Node nameNode = callNode.getFirstChild();
if (nameNode.getType() == Token.NAME &&
CONSTRUCTORS_WITHOUT_SIDE_EFFECTS.contains(nameNode.getString())) {
return false;
}
return true;
}
// A list of built-in object creation or primitive type cast functions that
// can also be called as constructors but lack side-effects.
// TODO(johnlenz): consider adding an extern annotation for this.
private static final Set<String> BUILTIN_FUNCTIONS_WITHOUT_SIDEEFFECTS =
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> ImmutableSet.of(
"Object", "Array", "String", "Number", "Boolean", "RegExp", "Error");
private static final Set<String> REGEXP_METHODS =
ImmutableSet.of("test", "exec");
private static final Set<String> STRING_REGEXP_METHODS =
ImmutableSet.of("match", "replace", "search", "split");
/**
* Returns true if calls to this function have side effects.
*
* @param callNode - function call node
*/
static boolean functionCallHasSideEffects(
Node callNode) {
return functionCallHasSideEffects(callNode, null);
}
/**
* Returns true if calls to this function have side effects.
*
* @param callNode The call node to inspected.
* @param compiler A compiler object to provide program state changing
* context information. Can be null.
*/
static boolean functionCallHasSideEffects(
Node callNode, @Nullable AbstractCompiler compiler) {
Preconditions.checkArgument(
callNode.getType() == Token.CALL,
"Expected CALL node, got " + Token.name(callNode.getType()));
if (callNode.isNoSideEffectsCall()) {
return false;
}
Node nameNode = callNode.getFirstChild();
// Built-in functions with no side effects.
if (nameNode.getType() == Token.NAME) {
String name = nameNode.getString();
if (BUILTIN_FUNCTIONS_WITHOUT_SIDEEFFECTS.contains(name)) {
return false;
}
} else if (nameNode.getType() == Token.GETPROP) {
// Functions in the "Math" namespace have no side effects.
if (nameNode.getFirstChild().getType() == Token.NAME) {
String namespaceName = nameNode.getFirstChild().getString();
if (namespaceName.equals("Math")) {
return false;
}
}
if (compiler != null && !compiler.hasRegExpGlobalReferences()) {
if (nameNode.getFirstChild().getType() == Token.REGEXP
&& REGEXP_METHODS.contains(nameNode.getLastChild().getString())) {
return false;
} else if (nameNode.getFirstChild().getType() == Token.STRING
&& STRING_REGEXP_METHODS.
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>contains(
nameNode.getLastChild().getString())) {
Node param = nameNode.getNext();
if (param != null &&
(param.getType() == Token.STRING
|| param.getType() == Token.REGEXP))
return false;
}
}
}
return true;
}
/**
* Returns true if the current node's type implies side effects.
*
* This is a non-recursive version of the may have side effects
* check; used to check wherever the current node's type is one of
* the reason's why a subtree has side effects.
*/
static boolean nodeTypeMayHaveSideEffects(Node n) {
return nodeTypeMayHaveSideEffects(n, null);
}
static boolean nodeTypeMayHaveSideEffects(Node n, AbstractCompiler compiler) {
if (isAssignmentOp(n)) {
return true;
}
switch(n.getType()) {
case Token.DELPROP:
case Token.DEC:
case Token.INC:
case Token.THROW:
return true;
case Token.CALL:
return NodeUtil.functionCallHasSideEffects(n, compiler);
case Token.NEW:
return NodeUtil.constructorCallHasSideEffects(n, compiler);
case Token.NAME:
// A variable definition.
return n.hasChildren();
default:
return false;
}
}
/**
* @return Whether the tree can be affected by side-effects or
* has side-effects.
*/
static boolean canBeSideEffected(Node n) {
Set<String> emptySet = Collections.emptySet();
return canBeSideEffected(n, emptySet);
}
/**
* @param knownConstants A set of names known to be constant value at
* node 'n' (such as locals that are last written before n can execute).
* @return Whether the tree can be affected by side-effects or
* has side-effects.
*/
static boolean canBeSideEffected(Node n, Set<String> knownConstants) {
switch (n.getType()) {
case Token.CALL:
case Token.NEW:
// Function calls or constructor can reference changed values.
// TODO(johnlenz): Add some mechanism for determining that functions
// are unaffected by side effects.
return true;
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>
case Token.NAME:
// Non-constant names values may have been changed.
return !isConstantName(n)
&& !knownConstants.contains(n.getString());
// Properties on constant NAMEs can still be side-effected.
case Token.GETPROP:
case Token.GETELEM:
return true;
case Token.FUNCTION:
// Function expression are not changed by side-effects,
// and function declarations are not part of expressions.
Preconditions.checkState(isFunctionExpression(n));
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (canBeSideEffected(c, knownConstants)) {
return true;
}
}
return false;
}
/*
* 0 comma ,
* 1 assignment = += -= *= /= %= <<= >>= >>>= &= ^= |=
* 2 conditional ?:
* 3 logical-or ||
* 4 logical-and &&
* 5 bitwise-or |
* 6 bitwise-xor ^
* 7 bitwise-and &
* 8 equality == !=
* 9 relational < <= > >=
* 10 bitwise shift << >> >>>
* 11 addition/subtraction + -
* 12 multiply/divide * / %
* 13 negation/increment ! ~ - ++ --
* 14 call, member () [] .
*/
static int precedence(int type) {
switch (type) {
case Token.COMMA: return 0;
case Token.ASSIGN_BITOR:
case Token.ASSIGN_BITXOR:
case Token.ASSIGN_BITAND:
case Token.ASSIGN_LSH:
case Token.ASSIGN_RSH:
case Token.ASSIGN_URSH:
case Token.ASSIGN_ADD:
case Token.ASSIGN_SUB:
case Token.ASSIGN_MUL:
case Token.ASSIGN_DIV:
case Token.ASSIGN_MOD:
case Token.ASSIGN: return 1;
case Token.HOOK: return 2; // ?: operator
case Token.OR: return 3;
case Token.AND: return 4;
case Token.BITOR: return 5;
case Token.BITXOR: return
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> == Token.SCRIPT || n.getType() == Token.BLOCK;
}
/**
* @return Whether the node is used as a statement.
*/
static boolean isStatement(Node n) {
Node parent = n.getParent();
// It is not possible to determine definitely if a node is a statement
// or not if it is not part of the AST. A FUNCTION node can be
// either part of an expression or a statement.
Preconditions.checkState(parent != null);
switch (parent.getType()) {
case Token.SCRIPT:
case Token.BLOCK:
case Token.LABEL:
return true;
default:
return false;
}
}
/** Whether the node is part of a switch statement. */
static boolean isSwitchCase(Node n) {
return n.getType() == Token.CASE || n.getType() == Token.DEFAULT;
}
/**
* @return Whether the name is a reference to a variable, function or
* function parameter (not a label or a empty function expression name).
*/
static boolean isReferenceName(Node n) {
return isName(n) && !n.getString().isEmpty();
}
/** @return Whether the node is a label name. */
static boolean isLabelName(Node n) {
return (n != null && n.getType() == Token.LABEL_NAME);
}
/** Whether the child node is the FINALLY block of a try. */
static boolean isTryFinallyNode(Node parent, Node child) {
return parent.getType() == Token.TRY && parent.getChildCount() == 3
&& child == parent.getLastChild();
}
/** Safely remove children while maintaining a valid node structure. */
static void removeChild(Node parent, Node node) {
// Node parent = node.getParent();
if (isStatementBlock(parent)
|| isSwitchCase(node)
|| isTryFinallyNode(parent, node)) {
// A statement in a block can simply be removed.
parent.removeChild(node);
} else if (parent.getType() == Token.VAR) {
if (parent.hasMoreThanOneChild()) {
parent.removeChild(node);
} else {
// Remove the node from the parent, so it can be reused.
parent.removeChild(node);
// This
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> node
* @return whether the given node is a function expression that is empty
*/
static boolean isEmptyFunctionExpression(Node node) {
return isFunctionExpression(node) && isEmptyBlock(node.getLastChild());
}
/**
* Determines if a function takes a variable number of arguments by
* looking for references to the "arguments" var_args object.
*/
static boolean isVarArgsFunction(Node function) {
Preconditions.checkArgument(isFunction(function));
return isNameReferenced(
function.getLastChild(),
"arguments",
new MatchNotFunction());
}
/**
* @return Whether node is a call to methodName.
* a.f(...)
* a['f'](...)
*/
static boolean isObjectCallMethod(Node callNode, String methodName) {
if (callNode.getType() == Token.CALL) {
Node functionIndentifyingExpression = callNode.getFirstChild();
if (isGet(functionIndentifyingExpression)) {
Node last = functionIndentifyingExpression.getLastChild();
if (last != null && last.getType() == Token.STRING) {
String propName = last.getString();
return (propName.equals(methodName));
}
}
}
return false;
}
/**
* @return Whether the callNode represents an expression in the form of:
* x.call(...)
* x['call'](...)
*/
static boolean isFunctionObjectCall(Node callNode) {
return isObjectCallMethod(callNode, "call");
}
/**
* @return Whether the callNode represents an expression in the form of:
* x.apply(...)
* x['apply'](...)
*/
static boolean isFunctionObjectApply(Node callNode) {
return isObjectCallMethod(callNode, "apply");
}
/**
* @return Whether the callNode represents an expression in the form of:
* x.call(...)
* x['call'](...)
* where x is a NAME node.
*/
static boolean isSimpleFunctionObjectCall(Node callNode) {
if (isFunctionObjectCall(callNode)) {
if (callNode.getFirstChild().getFirstChild().getType() == Token.NAME) {
return true;
}
}
return false;
}
/**
* Determines whether this node
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>(Node node, int type) {
return containsType(node, type, Predicates.<Node>alwaysTrue());
}
/**
* Given a node tree, finds all the VAR declarations in that tree that are
* not in an inner scope. Then adds a new VAR node at the top of the current
* scope that redeclares them, if necessary.
*/
static void redeclareVarsInsideBranch(Node branch) {
Collection<Node> vars = getVarsDeclaredInBranch(branch);
if (vars.isEmpty()) {
return;
}
Node parent = getAddingRoot(branch);
for (Node nameNode : vars) {
Node var = new Node(
Token.VAR,
Node.newString(Token.NAME, nameNode.getString())
.copyInformationFrom(nameNode))
.copyInformationFrom(nameNode);
copyNameAnnotations(nameNode, var.getFirstChild());
parent.addChildToFront(var);
}
}
/**
* Copy any annotations that follow a named value.
* @param source
* @param destination
*/
static void copyNameAnnotations(Node source, Node destination) {
if (source.getBooleanProp(Node.IS_CONSTANT_NAME)) {
destination.putBooleanProp(Node.IS_CONSTANT_NAME, true);
}
}
/**
* Gets a Node at the top of the current scope where we can add new var
* declarations as children.
*/
private static Node getAddingRoot(Node n) {
Node addingRoot = null;
Node ancestor = n;
while (null != (ancestor = ancestor.getParent())) {
int type = ancestor.getType();
if (type == Token.SCRIPT) {
addingRoot = ancestor;
break;
} else if (type == Token.FUNCTION) {
addingRoot = ancestor.getLastChild();
break;
}
}
// make sure that the adding root looks ok
Preconditions.checkState(addingRoot.getType() == Token.BLOCK ||
addingRoot.getType() == Token.SCRIPT);
Preconditions.checkState(addingRoot.getFirstChild() == null ||
addingRoot.getFirstChild().getType() != Token.SCRIPT);
return addingRoot;
}
/** Creates function name(params_0, ..., params_n) { body }. */
public static Node newFunctionNode
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> == Token.NAME) {
Node parent = n.getParent();
if (parent != null && parent.getType() == Token.VAR) {
String name = n.getString();
if (!vars.containsKey(name)) {
vars.put(name, n);
}
}
}
}
}
/**
* Retrieves vars declared in the current node tree, excluding descent scopes.
*/
public static Collection<Node> getVarsDeclaredInBranch(Node root) {
VarCollector collector = new VarCollector();
visitPreOrder(
root,
collector,
new MatchNotFunction());
return collector.vars.values();
}
/**
* @return {@code true} if the node an assignment to a prototype property of
* some constructor.
*/
static boolean isPrototypePropertyDeclaration(Node n) {
if (!isExprAssign(n)) {
return false;
}
return isPrototypeProperty(n.getFirstChild().getFirstChild());
}
static boolean isPrototypeProperty(Node n) {
String lhsString = n.getQualifiedName();
if (lhsString == null) {
return false;
}
int prototypeIdx = lhsString.indexOf(".prototype.");
return prototypeIdx != -1;
}
/**
* @return The class name part of a qualified prototype name.
*/
static Node getPrototypeClassName(Node qName) {
Node cur = qName;
while (isGetProp(cur)) {
if (cur.getLastChild().getString().equals("prototype")) {
return cur.getFirstChild();
} else {
cur = cur.getFirstChild();
}
}
return null;
}
/**
* @return The string property name part of a qualified prototype name.
*/
static String getPrototypePropertyName(Node qName) {
String qNameStr = qName.getQualifiedName();
int prototypeIdx = qNameStr.lastIndexOf(".prototype.");
int memberIndex = prototypeIdx + ".prototype".length() + 1;
return qNameStr.substring(memberIndex);
}
/**
* Create a node for an empty result expression:
* "void 0"
*/
static Node newUndefinedNode(Node srcReferenceNode) {
// TODO(johnlenz): Why this instead of the more common "undefined"?
Node node = new Node(
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>Token.VOID, Node.newNumber(0));
if (srcReferenceNode != null) {
node.copyInformationFromForTree(srcReferenceNode);
}
return node;
}
/**
* Create a VAR node containing the given name and initial value expression.
*/
static Node newVarNode(String name, Node value) {
Node nodeName = Node.newString(Token.NAME, name);
if (value != null) {
Preconditions.checkState(value.getNext() == null);
nodeName.addChildToBack(value);
nodeName.copyInformationFrom(value);
}
Node var = new Node(Token.VAR, nodeName)
.copyInformationFrom(nodeName);
return var;
}
/**
* A predicate for matching name nodes with the specified node.
*/
private static class MatchNameNode implements Predicate<Node>{
final String name;
MatchNameNode(String name){
this.name = name;
}
public boolean apply(Node n) {
return n.getType() == Token.NAME
&& n.getString().equals(name);
}
}
/**
* A predicate for matching nodes with the specified type.
*/
static class MatchNodeType implements Predicate<Node>{
final int type;
MatchNodeType(int type){
this.type = type;
}
public boolean apply(Node n) {
return n.getType() == type;
}
}
/**
* A predicate for matching var or function declarations.
*/
static class MatchDeclaration implements Predicate<Node> {
public boolean apply(Node n) {
return isFunctionDeclaration(n) || n.getType() == Token.VAR;
}
}
/**
* A predicate for matching anything except function nodes.
*/
static class MatchNotFunction implements Predicate<Node>{
public boolean apply(Node n) {
return !isFunction(n);
}
}
/**
* A predicate for matching statements without exiting the current scope.
*/
static class MatchShallowStatement implements Predicate<Node>{
public boolean apply(Node n) {
Node parent = n.getParent();
return n.getType() == Token.BLOCK
|| (!isFunction(n) && (parent == null
|| isControlStructure(parent)
|| isStatementBlock(parent)));
}
}
/**
* Finds the number
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>.FUNCTION);
return fnNode.getFirstChild().getNext();
}
/**
* Returns true if a name node represents a constant variable.
*
* <p>Determining whether a variable is constant has three steps:
* <ol>
* <li>In CodingConventionAnnotator, any name that matches the
* {@link CodingConvention#isConstant(String)} is annotated with an
* IS_CONSTANT_NAME property.
* <li>The normalize pass renames any variable with the IS_CONSTANT_NAME
* annotation and that is initialized to a constant value with
* a variable name inlucding $$constant.
* <li>Return true here if the variable includes $$constant in its name.
* </ol>
*
* @param node A NAME or STRING node
* @return True if the variable is constant
*/
static boolean isConstantName(Node node) {
return node.getBooleanProp(Node.IS_CONSTANT_NAME);
}
/** Whether the given name is constant by coding convention. */
static boolean isConstantByConvention(
CodingConvention convention, Node node, Node parent) {
String name = node.getString();
if (parent.getType() == Token.GETPROP &&
node == parent.getLastChild()) {
return convention.isConstantKey(name);
} else if (isObjectLitKey(node, parent)) {
return convention.isConstantKey(name);
} else {
return convention.isConstant(name);
}
}
/**
* @param nameNode A name node
* @return The JSDocInfo for the name node
*/
static JSDocInfo getInfoForNameNode(Node nameNode) {
JSDocInfo info = null;
Node parent = null;
if (nameNode != null) {
info = nameNode.getJSDocInfo();
parent = nameNode.getParent();
}
if (info == null && parent != null &&
((parent.getType() == Token.VAR && parent.hasOneChild()) ||
parent.getType() == Token.FUNCTION)) {
info = parent.getJSDocInfo();
}
return info;
}
/**
* Get the JSDocInfo for a function.
*/
static JSDocInfo getFunctionInfo(Node n) {
Preconditions.
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>/*
* Copyright 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.common.base.Preconditions;
import com.google.javascript.jscomp.AbstractCompiler;
import com.google.javascript.jscomp.CompilerPass;
import com.google.javascript.jscomp.NodeTraversal;
import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback;
import com.google.javascript.jscomp.NodeUtil;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.Token;
import com.google.javascript.rhino.jstype.TernaryValue;
/**
* Transform the structure of the AST so that the number of explicit exits
* are minimized.
*
* @author johnlenz@google.com (John Lenz)
*/
class MinimizeExitPoints
extends AbstractPostOrderCallback
implements CompilerPass {
AbstractCompiler compiler;
MinimizeExitPoints(AbstractCompiler compiler) {
this.compiler = compiler;
}
@Override
public void process(Node externs, Node root) {
NodeTraversal.traverse(compiler, root, this);
}
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
switch (n.getType()) {
case Token.LABEL:
tryMinimizeExits(
n.getLastChild(), Token.BREAK, n.getFirstChild().getString());
break;
case Token.FOR:
case Token.WHILE:
tryMinimizeExits(
NodeUtil.getLoopCodeBlock(n), Token.CONTINUE, null);
break;
case Token.DO
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>ifNode.getNext() != null) {
// Move siblings of the if block into the opposite
// logic block of the exit.
Node newDestBlock = new Node(Token.BLOCK).copyInformationFrom(ifNode);
if (destBlock == null) {
// Only possible if this is the false block.
ifNode.addChildToBack(newDestBlock);
} else if (destBlock.getType() == Token.EMPTY) {
// Use the new block.
ifNode.replaceChild(destBlock, newDestBlock);
} else if (destBlock.getType() == Token.BLOCK) {
// Reuse the existing block.
newDestBlock = destBlock;
} else {
// Add the existing statement to the new block.
ifNode.replaceChild(destBlock, newDestBlock);
newDestBlock.addChildToBack(destBlock);
}
// Move all the if node's following siblings.
moveAllFollowing(ifNode, ifNode.getParent(), newDestBlock);
}
// Get rid of the "exit", replace with an empty item if needed.
NodeUtil.removeChild(exitNodeParent, exitNode);
compiler.reportCodeChange();
}
/**
* Determines if n matches the type and name for the following types of
* "exits":
* - return without values
* - continues and breaks with or without names.
* @param n The node to inspect.
* @param type The Token type to look for.
* @param labelName The name that must be associated with the exit type.
* @nullable labelName non-null only for breaks associated with labels.
* @return Whether the node matches the specified block-exit type.
*/
static private boolean matchingExitNode(Node n, int type, String labelName) {
if (n.getType() == type) {
if (type == Token.RETURN) {
// only returns without expressions.
return !n.hasChildren();
} else {
if (labelName == null) {
return !n.hasChildren();
} else {
return n.hasChildren()
&& labelName.equals(n.getFirstChild().getString());
}
}
}
return false;
}
/**
* Move all the child nodes following start in srcParent to the end of
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>SERVE_BLOCK);
// second child contains the catch block, or nothing if there
// isn't a catch block
Node catchblock = first.getNext().getFirstChild();
if (catchblock != null) {
add(catchblock);
}
if (childCount == 3) {
add("finally");
add(last, Context.PRESERVE_BLOCK);
}
break;
}
case Token.CATCH:
Preconditions.checkState(childCount == 2);
add("catch(");
add(first);
add(")");
add(last, Context.PRESERVE_BLOCK);
break;
case Token.THROW:
Preconditions.checkState(childCount == 1);
add("throw");
add(first);
// Must have a ';' after a throw statement, otherwise safari can't
// parse this.
cc.endStatement(true);
break;
case Token.RETURN:
add("return");
if (childCount == 1) {
add(first);
} else {
Preconditions.checkState(childCount == 0);
}
cc.endStatement();
break;
case Token.VAR:
if (first != null) {
add("var ");
addList(first, false, getContextForNoInOperator(context));
}
break;
case Token.LABEL_NAME:
Preconditions.checkState(!n.getString().isEmpty());
addIdentifier(n.getString());
break;
case Token.NAME:
if (first == null || first.getType() == Token.EMPTY) {
addIdentifier(n.getString());
} else {
Preconditions.checkState(childCount == 1);
addIdentifier(n.getString());
cc.addOp("=", true);
if (first.getType() == Token.COMMA) {
addExpr(first, NodeUtil.precedence(Token.ASSIGN));
} else {
// Add expression, consider nearby code at lowest level of
// precedence.
addExpr(first, 0, getContextForNoInOperator(context));
}
}
break;
case Token.ARRAYLIT:
add("[");
addList(first, (int[]) n.getProp(Node.SKIP_INDEXES_PROP));
add("]");
break;
case Token.LP:
add("
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>(");
addList(first);
add(")");
break;
case Token.COMMA:
Preconditions.checkState(childCount == 2);
addList(first, false, context);
break;
case Token.NUMBER:
Preconditions.checkState(childCount == 0);
cc.addNumber(n.getDouble());
break;
case Token.TYPEOF:
case Token.VOID:
case Token.NOT:
case Token.BITNOT:
case Token.POS:
case Token.NEG: {
// All of these unary operators are right-associative
Preconditions.checkState(childCount == 1);
cc.addOp(NodeUtil.opToStrNoFail(type), false);
addExpr(first, NodeUtil.precedence(type));
break;
}
case Token.HOOK: {
Preconditions.checkState(childCount == 3);
int p = NodeUtil.precedence(type);
addLeftExpr(first, p + 1, context);
cc.addOp("?", true);
addExpr(first.getNext(), 1);
cc.addOp(":", true);
addExpr(last, 1);
break;
}
case Token.REGEXP:
if (first.getType() != Token.STRING ||
last.getType() != Token.STRING) {
throw new Error("Expected children to be strings");
}
String regexp = regexpEscape(first.getString(), outputCharsetEncoder);
// I only use one .add because whitespace matters
if (childCount == 2) {
add(regexp + last.getString());
} else {
Preconditions.checkState(childCount == 1);
add(regexp);
}
break;
case Token.GET_REF:
add(first);
break;
case Token.REF_SPECIAL:
Preconditions.checkState(childCount == 1);
add(first);
add(".");
add((String) n.getProp(Node.NAME_PROP));
break;
case Token.FUNCTION:
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
Preconditions.checkState(childCount == 3);
boolean funcNeedsParens = (context == Context.START_OF_EXPR);
if (func
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>checkState(childCount == 2);
add("do");
addNonEmptyStatement(first, Context.OTHER, false);
add("while(");
add(last);
add(")");
cc.endStatement();
break;
case Token.WHILE:
Preconditions.checkState(childCount == 2);
add("while(");
add(first);
add(")");
addNonEmptyStatement(
last, getContextForNonEmptyExpression(context), false);
break;
case Token.EMPTY:
Preconditions.checkState(childCount == 0);
break;
case Token.GETPROP: {
Preconditions.checkState(
childCount == 2,
"Bad GETPROP: expected 2 children, but got %s", childCount);
Preconditions.checkState(
last.getType() == Token.STRING,
"Bad GETPROP: RHS should be STRING");
boolean needsParens = (first.getType() == Token.NUMBER);
if (needsParens) {
add("(");
}
addLeftExpr(first, NodeUtil.precedence(type), context);
if (needsParens) {
add(")");
}
add(".");
addIdentifier(last.getString());
break;
}
case Token.GETELEM:
Preconditions.checkState(
childCount == 2,
"Bad GETELEM: expected 2 children but got %s", childCount);
addLeftExpr(first, NodeUtil.precedence(type), context);
add("[");
add(first.getNext());
add("]");
break;
case Token.WITH:
Preconditions.checkState(childCount == 2);
add("with(");
add(first);
add(")");
addNonEmptyStatement(
last, getContextForNonEmptyExpression(context), false);
break;
case Token.INC:
case Token.DEC: {
Preconditions.checkState(childCount == 1);
String o = type == Token.INC ? "++" : "--";
int postProp = n.getIntProp(Node.INCRDECR_PROP);
// A non-zero post-prop value indicates a post inc/dec, default of zero
// is a pre-inc/dec.
if (postProp != 0) {
addLeft
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>Name(type));
break;
case Token.CONTINUE:
Preconditions.checkState(childCount <= 1);
add("continue");
if (childCount == 1) {
if (first.getType() != Token.LABEL_NAME) {
throw new Error("Unexpected token type. Should be LABEL_NAME.");
}
add(" ");
add(first);
}
cc.endStatement();
break;
case Token.DEBUGGER:
Preconditions.checkState(childCount == 0);
add("debugger");
cc.endStatement();
break;
case Token.BREAK:
Preconditions.checkState(childCount <= 1);
add("break");
if (childCount == 1) {
if (first.getType() != Token.LABEL_NAME) {
throw new Error("Unexpected token type. Should be LABEL_NAME.");
}
add(" ");
add(first);
}
cc.endStatement();
break;
case Token.EXPR_VOID:
throw new Error("Unexpected EXPR_VOID. Should be EXPR_RESULT.");
case Token.EXPR_RESULT:
Preconditions.checkState(childCount == 1);
add(first, Context.START_OF_EXPR);
cc.endStatement();
break;
case Token.NEW:
add("new ");
int precedence = NodeUtil.precedence(type);
// If the first child contains a CALL, then claim higher precedence
// to force parentheses. Otherwise, when parsed, NEW will bind to the
// first viable parentheses (don't traverse into functions).
if (NodeUtil.containsType(first, Token.CALL, new MatchNotFunction())) {
precedence = NodeUtil.precedence(first.getType()) + 1;
}
addExpr(first, precedence);
// '()' is optional when no arguments are present
Node next = first.getNext();
if (next != null) {
add("(");
addList(next);
add(")");
}
break;
case Token.STRING:
Preconditions.checkState(childCount == 0);
add(jsString(n.getString(), outputCharsetEncoder));
break;
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>.OBJECTLIT: {
Preconditions.checkState(childCount % 2 == 0);
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext().getNext()) {
if (c != first) {
cc.listSeparator();
}
// Object literal property names don't have to be quoted if they are
// not JavaScript keywords
if (c.getType() == Token.STRING &&
!TokenStream.isKeyword(c.getString()) &&
TokenStream.isJSIdentifier(c.getString()) &&
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(c.getString())) {
add(c.getString());
} else {
addExpr(c, 1);
}
add(":");
addExpr(c.getNext(), 1);
}
add("}");
if (needsParens) {
add(")");
}
break;
}
case Token.SWITCH:
add("switch(");
add(first);
add(")");
cc.beginBlock();
addAllSiblings(first.getNext());
cc.endBlock(context == Context.STATEMENT);
break;
case Token.CASE:
Preconditions.checkState(childCount == 2);
add("case ");
add(first);
addCaseBody(last);
break;
case Token.DEFAULT:
Preconditions.checkState(childCount == 1);
add("default");
addCaseBody(first);
break;
case Token.LABEL:
Preconditions.checkState(childCount == 2);
if (first.getType() != Token.LABEL_NAME) {
throw new Error("Unexpected token type. Should be LABEL_NAME.");
}
add(first);
add(":");
addNonEmptyStatement(
last, getContextForNonEmptyExpression(context), true);
break;
// This node is auto generated in anonymous functions and should just get
// ignored for our purposes.
case Token.SETNAME:
break;
default:
throw new Error("Unknown type " + type + "\n" + n.toStringTree());
}
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> cc.endSourceMapping(n);
}
/**
* @return Whether the name is an indirect eval.
*/
private boolean isIndirectEval(Node n) {
return n.getType() == Token.NAME && "eval".equals(n.getString()) &&
!n.getBooleanProp(Node.DIRECT_EVAL);
}
/**
* Adds a block or expression, substituting a VOID with an empty statement.
* This is used for "for (...);" and "if (...);" type statements.
*
* @param n The node to print.
* @param context The context to determine how the node should be printed.
*/
private void addNonEmptyStatement(
Node n, Context context, boolean allowNonBlockChild) {
Node nodeToProcess = n;
if (!allowNonBlockChild && n.getType() != Token.BLOCK) {
throw new Error("Missing BLOCK child.");
}
// Strip unneeded blocks, that is blocks with <2 children unless
// the CodePrinter specifically wants to keep them.
if (n.getType() == Token.BLOCK) {
int count = getNonEmptyChildCount(n, 2);
if (count == 0) {
if (cc.shouldPreserveExtraBlocks()) {
cc.beginBlock();
cc.endBlock(cc.breakAfterBlockFor(n, context == Context.STATEMENT));
} else {
cc.endStatement(true);
}
return;
}
if (count == 1) {
// Hack around a couple of browser bugs:
// Safari needs a block around function declarations.
// IE6/7 needs a block around DOs.
Node firstAndOnlyChild = getFirstNonEmptyChild(n);
boolean alwaysWrapInBlock = cc.shouldPreserveExtraBlocks();
if (alwaysWrapInBlock || isOneExactlyFunctionOrDo(firstAndOnlyChild)) {
cc.beginBlock();
add(firstAndOnlyChild, Context.STATEMENT);
cc.maybeLineBreak();
cc.endBlock(cc.breakAfterBlockFor(n, context == Context.STATEMENT));
return;
} else {
// Continue with the only child.
nodeToProcess = firstAndOnlyChild;
}
}
if (count > 1) {
context = Context.PRESERVE_
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> number affects JavaScript semantics as detailed
* in the overview documentation.
*
* @return an integer that is one of VERSION_1_0, VERSION_1_1, etc.
*/
public final int getLanguageVersion()
{
return version;
}
/**
* Set the language version.
*
* <p>
* Setting the language version will affect functions and scripts compiled
* subsequently. See the overview documentation for version-specific
* behavior.
*
* @param version the version as specified by VERSION_1_0, VERSION_1_1, etc.
*/
public void setLanguageVersion(int version)
{
if (sealed) onSealedMutation();
checkLanguageVersion(version);
Object listeners = propertyListeners;
if (listeners != null && version != this.version) {
firePropertyChangeImpl(listeners, languageVersionProperty,
new Integer(this.version),
new Integer(version));
}
this.version = version;
}
public static boolean isValidLanguageVersion(int version)
{
switch (version) {
case VERSION_DEFAULT:
case VERSION_1_0:
case VERSION_1_1:
case VERSION_1_2:
case VERSION_1_3:
case VERSION_1_4:
case VERSION_1_5:
case VERSION_1_6:
return true;
}
return false;
}
public static void checkLanguageVersion(int version)
{
if (isValidLanguageVersion(version)) {
return;
}
throw new IllegalArgumentException("Bad language version: "+version);
}
/**
* Get the implementation version.
*
* <p>
* The implementation version is of the form
* <pre>
* "<i>name langVer</i> <code>release</code> <i>relNum date</i>"
* </pre>
* where <i>name</i> is the name of the product, <i>langVer</i> is
* the language version, <i>relNum</i> is the release number, and
* <i>date</i> is the release date for that specific
* release in the form "yyyy mm dd".
*
* @return a string that encodes the product, language version, release
*
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>p>
* @param key the key used to index the value
* @param value the value to save
*/
public final void putThreadLocal(Object key, Object value)
{
if (sealed) onSealedMutation();
if (hashtable == null)
hashtable = new Hashtable<Object, Object>();
hashtable.put(key, value);
}
/**
* Remove values from thread-local storage.
* @param key the key for the entry to remove.
* @since 1.5 release 2
*/
public final void removeThreadLocal(Object key)
{
if (sealed) onSealedMutation();
if (hashtable == null)
return;
hashtable.remove(key);
}
/**
* @deprecated
* @see #FEATURE_DYNAMIC_SCOPE
* @see #hasFeature(int)
*/
@Deprecated
public final boolean hasCompileFunctionsWithDynamicScope()
{
return compileFunctionsWithDynamicScopeFlag;
}
/**
* @deprecated
* @see #FEATURE_DYNAMIC_SCOPE
* @see #hasFeature(int)
*/
@Deprecated
public final void setCompileFunctionsWithDynamicScope(boolean flag)
{
if (sealed) onSealedMutation();
compileFunctionsWithDynamicScopeFlag = flag;
}
/**
* Return the debugger context data associated with current context.
* @return the debugger data, or null if debugger is not attached
*/
public final Object getDebuggerContextData()
{
return debuggerData;
}
/**
* Implementation of {@link Context#hasFeature(int featureIndex)}.
* This can be used to customize {@link Context} without introducing
* additional subclasses.
*/
protected boolean hasFeature(int featureIndex)
{
int version;
switch (featureIndex) {
case Context.FEATURE_NON_ECMA_GET_YEAR:
/*
* During the great date rewrite of 1.3, we tried to track the
* evolving ECMA standard, which then had a definition of
* getYear which always subtracted 1900. Which we
* implemented, not realizing that it was incompatible with
* the old behavior... now, rather than thrash the behavior
* yet again, we've decided to leave it with the - 1
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>900
* behavior and point people to the getFullYear method. But
* we try to protect existing scripts that have specified a
* version...
*/
version = getLanguageVersion();
return (version == Context.VERSION_1_0
|| version == Context.VERSION_1_1
|| version == Context.VERSION_1_2);
case Context.FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME:
return false;
case Context.FEATURE_RESERVED_KEYWORD_AS_IDENTIFIER:
return false;
case Context.FEATURE_TO_STRING_AS_SOURCE:
version = getLanguageVersion();
return version == Context.VERSION_1_2;
case Context.FEATURE_PARENT_PROTO_PROPRTIES:
return true;
case Context.FEATURE_E4X:
version = getLanguageVersion();
return (version == Context.VERSION_DEFAULT
|| version >= Context.VERSION_1_6);
case Context.FEATURE_DYNAMIC_SCOPE:
return false;
case Context.FEATURE_STRICT_VARS:
return false;
case Context.FEATURE_STRICT_EVAL:
return false;
case FEATURE_STRICT_MODE:
// Make JSCompiler run in non=strict mode always.
return false;
case FEATURE_WARNING_AS_ERROR:
// Let warnings stay warnings for now.
return false;
}
// It is a bug to call the method with unknown featureIndex
throw new IllegalArgumentException(String.valueOf(featureIndex));
}
/**
* Get/Set threshold of executed instructions counter that triggers call to
* <code>observeInstructionCount()</code>.
* When the threshold is zero, instruction counting is disabled,
* otherwise each time the run-time executes at least the threshold value
* of script instructions, <code>observeInstructionCount()</code> will
* be called.
*/
public final int getInstructionObserverThreshold()
{
return instructionThreshold;
}
public final void setInstructionObserverThreshold(int threshold)
{
if (sealed) onSealedMutation();
if (threshold < 0) throw new IllegalArgumentException();
instructionThreshold = threshold;
}
/********** end of API **********/
static Context getContext() {
Context cx = getCurrentContext();
if (cx == null) {
throw new RuntimeException(
"No Context associated with current Thread
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>");
}
return cx;
}
final boolean isVersionECMA1()
{
return version == VERSION_DEFAULT || version >= VERSION_1_3;
}
static String getSourcePositionFromStack(int[] linep)
{
Context cx = getCurrentContext();
if (cx == null)
return null;
/**
* A bit of a hack, but the only way to get filename and line
* number from an enclosing frame.
*/
CharArrayWriter writer = new CharArrayWriter();
RuntimeException re = new RuntimeException();
re.printStackTrace(new PrintWriter(writer));
String s = writer.toString();
int open = -1;
int close = -1;
int colon = -1;
for (int i=0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == ':')
colon = i;
else if (c == '(')
open = i;
else if (c == ')')
close = i;
else if (c == '\n' && open != -1 && close != -1 && colon != -1 &&
open < colon && colon < close)
{
String fileStr = s.substring(open + 1, colon);
if (!fileStr.endsWith(".java")) {
String lineStr = s.substring(colon + 1, close);
try {
linep[0] = Integer.parseInt(lineStr);
if (linep[0] < 0) {
linep[0] = 0;
}
return fileStr;
}
catch (NumberFormatException e) {
// fall through
}
}
open = close = colon = -1;
}
}
return null;
}
public final boolean isGeneratingDebugChanged()
{
return generatingDebugChanged;
}
/**
* Add a name to the list of names forcing the creation of real
* activation objects for functions.
*
* @param name the name of the object to add to the list
*/
public void addActivationName(String name)
{
if (sealed) onSealedMutation();
if (activationNames == null)
activationNames = new Hashtable<Object, Object>(5);
activationNames.put(name, name);
}
/**
*
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> Check whether the name is in the list of names of objects
* forcing the creation of activation objects.
*
* @param name the name of the object to test
*
* @return true if an function activation object is needed.
*/
public final boolean isActivationNeeded(String name)
{
return activationNames != null && activationNames.containsKey(name);
}
/**
* Remove a name from the list of names forcing the creation of real
* activation objects for functions.
*
* @param name the name of the object to remove from the list
*/
public void removeActivationName(String name)
{
if (sealed) onSealedMutation();
if (activationNames != null)
activationNames.remove(name);
}
private static String implementationVersion;
private boolean sealed;
private Object sealKey;
// for Objects, Arrays to tag themselves as being printed out,
// so they don't print themselves out recursively.
// Use ObjToIntMap instead of java.util.HashSet for JDK 1.1 compatibility
ObjToIntMap iterating;
Object interpreterSecurityDomain;
int version;
private ErrorReporter errorReporter;
private Locale locale;
private boolean generatingDebug;
private boolean generatingDebugChanged;
private boolean generatingSource=true;
boolean compileFunctionsWithDynamicScopeFlag;
boolean useDynamicScope;
private Object debuggerData;
private int enterCount;
private int optimizationLevel;
private Object propertyListeners;
private Hashtable<Object, Object> hashtable;
/**
* This is the list of names of objects forcing the creation of
* function activation records.
*/
Hashtable<Object, Object> activationNames;
// For the interpreter to store the last frame for error reports etc.
Object lastInterpreterFrame;
// For the interpreter to store information about previous invocations
// interpreter invocations
ObjArray previousInterpreterInvocations;
// For instruction counting (interpreter only)
int instructionCount;
int instructionThreshold;
// It can be used to return the second index-like result from function
int scratchIndex;
// It can be used to return the second uint32 result from function
long scratchUint32;
}
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>:
*
* <pre>
* class MyCommandLineRunner extends
* AbstractCommandLineRunner<MyCompiler, MyOptions> {
* MyCommandLineRunner(String[] args) {
* super(args);
* }
*
* @Override
* protected MyOptions createOptions() {
* MyOptions options = new MyOptions();
* CompilerFlagTranslator.setOptionsFromFlags(options);
* addMyCrazyCompilerPassThatOutputsAnExtraFile(options);
* return options;
* }
*
* @Override
* protected MyCompiler createCompiler() {
* return new MyCompiler();
* }
*
* public static void main(String[] args) {
* (new MyCommandLineRunner(args)).run();
* }
* }
* </pre>
*
* @author bolinfest@google.com (Michael Bolin)
*/
abstract class AbstractCommandLineRunner<A extends Compiler,
B extends CompilerOptions> {
private final CommandLineConfig config;
private Appendable out;
private final PrintStream err;
private A compiler;
private Charset inputCharset;
private String outputCharset;
private boolean testMode = false;
private Supplier<List<JSSourceFile>> externsSupplierForTesting = null;
private Supplier<List<JSSourceFile>> inputsSupplierForTesting = null;
private Supplier<List<JSModule>> modulesSupplierForTesting = null;
private Function<Integer, Boolean> exitCodeReceiverForTesting = null;
// Bookkeeping to measure optimal phase orderings.
private static final int NUM_RUNS_TO_DETERMINE_OPTIMAL_ORDER = 100;
private final RunTimeStats runTimeStats = new RunTimeStats();
AbstractCommandLineRunner() {
this(System.out, System.err);
}
AbstractCommandLineRunner(PrintStream out, PrintStream err) {
this.config = new CommandLineConfig();
this.out = out;
this.err = err;
}
/**
* Put the command line runner into test mode. In test mode,
* all outputs will be blackholed.
* @param externsSupplier A provider for externs.
* @param inputsSupplier A provider for source inputs
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>.
* @param modulesSupplier A provider for modules. Only one of inputsSupplier
* and modulesSupplier may be non-null.
* @param exitCodeReceiver A receiver for the status code that would
* have been passed to System.exit in non-test mode.
*/
@VisibleForTesting
void enableTestMode(
Supplier<List<JSSourceFile>> externsSupplier,
Supplier<List<JSSourceFile>> inputsSupplier,
Supplier<List<JSModule>> modulesSupplier,
Function<Integer, Boolean> exitCodeReceiver) {
Preconditions.checkArgument(
inputsSupplier == null ^ modulesSupplier == null);
testMode = true;
this.externsSupplierForTesting = externsSupplier;
this.inputsSupplierForTesting = inputsSupplier;
this.modulesSupplierForTesting = modulesSupplier;
this.exitCodeReceiverForTesting = exitCodeReceiver;
}
/**
* Returns whether we're in test mode.
*/
protected boolean isInTestMode() {
return testMode;
}
/**
* Get the command line config, so that it can be initialized.
*/
protected CommandLineConfig getCommandLineConfig() {
return config;
}
/**
* Returns the instance of the Compiler to use when {@link #run()} is
* called.
*/
protected abstract A createCompiler();
/**
* Returns the instance of the Options to use when {@link #run()} is called.
* createCompiler() is called before createOptions(), so getCompiler()
* will not return null when createOptions() is called.
*/
protected abstract B createOptions();
/**
* The warning classes that are available from the command-line.
*/
protected DiagnosticGroups getDiagnosticGroups() {
if (compiler == null) {
return new DiagnosticGroups();
}
return compiler.getDiagnosticGroups();
}
/** No longer does anything. */
@Deprecated
protected void initOptionsFromFlags(CompilerOptions options) {}
/**
* Sets options based on the configurations set flags API.
* Called during the run() run() method.
* If you want to ignore the flags API, or intepret flags your own way,
* then you should override this method.
*/
final protected void setRunOptions(CompilerOptions options)
throws FlagUsageException, IOException {
DiagnosticGroups diagnosticGroups = getDiagnosticGroups();
diagnosticGroups
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>.setWarningLevels(
options, config.jscompError, CheckLevel.ERROR);
diagnosticGroups.setWarningLevels(
options, config.jscompWarning, CheckLevel.WARNING);
diagnosticGroups.setWarningLevels(
options, config.jscompOff, CheckLevel.OFF);
createDefineReplacements(config.define, options);
options.manageClosureDependencies = config.manageClosureDependencies;
options.devMode = config.jscompDevMode;
options.setCodingConvention(config.codingConvention);
options.setSummaryDetailLevel(config.summaryDetailLevel);
outputCharset = options.outputCharset = getOutputCharset();
inputCharset = getInputCharset();
if (config.jsOutputFile.length() > 0) {
options.jsOutputFile = config.jsOutputFile;
}
if (config.createSourceMap.length() > 0) {
options.sourceMapOutputPath = config.createSourceMap;
}
options.sourceMapDetailLevel = config.sourceMapDetailLevel;
if (!config.variableMapInputFile.equals("")) {
options.inputVariableMapSerialized =
VariableMap.load(config.variableMapInputFile).toBytes();
}
if (!config.propertyMapInputFile.equals("")) {
options.inputPropertyMapSerialized =
VariableMap.load(config.propertyMapInputFile).toBytes();
}
}
final protected A getCompiler() {
return compiler;
}
/**
* Runs the Compiler and calls System.exit() with the exit status of the
* compiler.
*/
final public void run() {
int result = 0;
int runs = 1;
if (config.computePhaseOrdering) {
runs = NUM_RUNS_TO_DETERMINE_OPTIMAL_ORDER;
PhaseOptimizer.randomizeLoops();
}
try {
for (int i = 0; i < runs && result == 0; i++) {
runTimeStats.recordStartRun();
result = doRun();
runTimeStats.recordEndRun();
}
} catch (AbstractCommandLineRunner.FlagUsageException e) {
System.err.println(e.getMessage());
result = -1;
} catch (Throwable t) {
t.printStackTrace();
result = -2;
}
if (
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>config.computePhaseOrdering) {
runTimeStats.outputBestPhaseOrdering();
}
if (testMode) {
exitCodeReceiverForTesting.apply(result);
} else {
System.exit(result);
}
}
/**
* Returns the PrintStream for writing errors associated with this
* AbstractCommandLineRunner.
*/
protected PrintStream getErrorPrintStream() {
return err;
}
/**
* An exception thrown when command-line flags are used incorrectly.
*/
protected static class FlagUsageException extends Exception {
private static final long serialVersionUID = 1L;
FlagUsageException(String message) {
super(message);
}
}
/**
* Creates inputs from a list of files.
*
* @param files A list of filenames
* @param allowStdIn Whether '-' is allowed appear as a filename to represent
* stdin. If true, '-' is only allowed to appear once.
* @return An array of inputs
*/
private List<JSSourceFile> createInputs(List<String> files,
boolean allowStdIn) throws FlagUsageException, IOException {
List<JSSourceFile> inputs = new ArrayList<JSSourceFile>(files.size());
boolean usingStdin = false;
for (String filename : files) {
if (!"-".equals(filename)) {
JSSourceFile newFile = JSSourceFile.fromFile(filename, inputCharset);
inputs.add(newFile);
} else {
if (!allowStdIn) {
throw new FlagUsageException("Can't specify stdin.");
}
if (usingStdin) {
throw new FlagUsageException("Can't specify stdin twice.");
}
inputs.add(JSSourceFile.fromInputStream("stdin", System.in));
usingStdin = true;
}
}
return inputs;
}
/**
* Creates js source code inputs from a list of files.
*/
private List<JSSourceFile> createSourceInputs(List<String> files)
throws FlagUsageException, IOException {
if (isInTestMode()) {
return inputsSupplierForTesting.get();
}
if (files.isEmpty()) {
files = Collections.singletonList("-");
}
try {
return createInputs(files, true);
} catch (FlagUsageException e) {
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>
if (compiler != null && compiler.getSourceMap() != null) {
compiler.getSourceMap().setWrapperPrefix(prefix);
}
} else {
out.append(code);
out.append('\n');
}
}
/**
* Creates any directories necessary to write a file that will have a given
* path prefix.
*/
private static void maybeCreateDirsForPath(String pathPrefix) {
if (pathPrefix.length() > 0) {
String dirName =
pathPrefix.charAt(pathPrefix.length() - 1) == File.separatorChar
? pathPrefix.substring(0, pathPrefix.length() - 1) : new File(
pathPrefix).getParent();
if (dirName != null) {
new File(dirName).mkdirs();
}
}
}
/**
* Parses command-line arguments and runs the compiler.
*
* @return system exit status
*/
protected int doRun() throws FlagUsageException, IOException {
Compiler.setLoggingLevel(Level.parse(config.loggingLevel));
List<JSSourceFile> externs = createExterns();
compiler = createCompiler();
B options = createOptions();
List<JSModule> modules = null;
Result result;
setRunOptions(options);
boolean writeOutputToFile = !options.jsOutputFile.isEmpty();
if (writeOutputToFile) {
out = fileNameToOutputWriter(options.jsOutputFile);
} else if (out instanceof OutputStream) {
out = streamToOutputWriter((OutputStream) out);
}
List<String> jsFiles = config.js;
List<String> moduleSpecs = config.module;
if (!moduleSpecs.isEmpty()) {
modules = createJsModules(moduleSpecs, jsFiles);
result = compiler.compileModules(externs, modules, options);
} else {
List<JSSourceFile> inputs = createSourceInputs(jsFiles);
result = compiler.compile(externs, inputs, options);
}
int errCode = processResults(result, modules, options);
// Close the output if we are writing to a file.
if (out instanceof Closeable) {
((Closeable)out).close();
}
return errCode;
}
/**
* Processes the results of the compile job,
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> and returns an error code.
*/
int processResults(Result result, List<JSModule> modules, B options)
throws FlagUsageException, IOException {
if (config.computePhaseOrdering) {
return 0;
}
if (config.printPassGraph) {
if (compiler.getRoot() == null) {
return 1;
} else {
out.append(DotFormatter.toDot(compiler.getPassConfig().getPassGraph()));
out.append('\n');
return 0;
}
}
if (config.printAst) {
if (compiler.getRoot() == null) {
return 1;
} else {
ControlFlowGraph<Node> cfg = compiler.computeCFG();
DotFormatter.appendDot(compiler.getRoot(), cfg, out);
out.append('\n');
return 0;
}
}
if (config.printTree) {
if (compiler.getRoot() == null) {
out.append("Code contains errors; no tree was generated.\n");
return 1;
} else {
compiler.getRoot().appendStringTree(out);
out.append("\n");
return 0;
}
}
if (result.success) {
if (modules == null) {
writeOutput(out, compiler, compiler.toSource(), config.outputWrapper,
config.outputWrapperMarker);
// Output the source map if requested.
outputSourceMap(options);
} else {
String moduleFilePrefix = config.moduleOutputPathPrefix;
maybeCreateDirsForPath(moduleFilePrefix);
Map<String, String> moduleWrappers =
parseModuleWrappers(config.moduleWrapper, modules);
// If the source map path is in fact a pattern for each
// module, create a stream per-module. Otherwise, create
// a single source map.
Writer mapOut = null;
if (!shouldGenerateMapPerModule(options)) {
mapOut = fileNameToOutputWriter(expandSourceMapPath(options, null));
}
for (JSModule m : modules) {
if (shouldGenerateMapPerModule(options)) {
mapOut = fileNameToOutputWriter(expandSourceMapPath(options, m));
}
Writer writer = fileNameToOutputWriter(
moduleFilePrefix + m.getName() + ".js");
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>
if (options.sourceMapOutputPath != null) {
compiler.getSourceMap().reset();
}
writeOutput(writer, compiler, compiler.toSource(m), moduleWrappers.get(
m.getName()), "%s");
if (options.sourceMapOutputPath != null) {
compiler.getSourceMap().appendTo(mapOut, m.getName());
}
writer.close();
if (shouldGenerateMapPerModule(options) && mapOut != null) {
mapOut.close();
mapOut = null;
}
}
if (mapOut != null) {
mapOut.close();
}
}
// Output the externs if required.
if (options.externExportsPath != null) {
Writer eeOut =
openExternExportsStream(options, options.jsOutputFile);
eeOut.append(result.externExport);
eeOut.close();
}
// Output the variable and property name maps if requested.
outputNameMaps(options);
// Output the manifest if requested.
outputManifest();
}
// return 0 if no errors, the error count otherwise
return Math.min(result.errors.length, 0x7f);
}
/**
* Query the flag for the input charset, and return a Charset object
* representing the selection.
*
* @return Charset to use when reading inputs
* @throws FlagUsageException if flag is not a valid Charset name.
*/
private Charset getInputCharset() throws FlagUsageException {
if (!config.charset.isEmpty()) {
if (!Charset.isSupported(config.charset)) {
throw new FlagUsageException(config.charset +
" is not a valid charset name.");
}
return Charset.forName(config.charset);
}
return Charsets.UTF_8;
}
/**
* Query the flag for the output charset.
*
* Let the outputCharset be the same as the input charset... except if
* we're reading in UTF-8 by default. By tradition, we've always
* output ASCII to avoid various hiccups with different browsers,
* proxies and firewalls.
*
* @return Name of the charset to use when writing outputs. Guaranteed to
* be a supported charset.
* @throws FlagUsageException if flag is not a valid
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> Charset name.
*/
private String getOutputCharset() throws FlagUsageException {
if (!config.charset.isEmpty()) {
if (!Charset.isSupported(config.charset)) {
throw new FlagUsageException(config.charset +
" is not a valid charset name.");
}
return config.charset;
}
return "US-ASCII";
}
protected List<JSSourceFile> createExterns() throws FlagUsageException,
IOException {
return isInTestMode() ? externsSupplierForTesting.get() :
createExternInputs(config.externs);
}
/**
* Returns true if and only if a source map file should be generated for each
* module, as opposed to one unified map. This is specified by having the
* source map pattern include the %outname% variable.
*/
private boolean shouldGenerateMapPerModule(B options) {
return options.sourceMapOutputPath != null
&& options.sourceMapOutputPath.contains("%outname%");
}
/**
* Returns a stream for outputting the generated externs file.
*
* @param options The options to the Compiler.
* @param path The path of the generated JS source file.
*
* @return The stream or null if no extern-ed exports are being generated.
*/
private Writer openExternExportsStream(B options,
String path) throws IOException {
if (options.externExportsPath == null) {
return null;
}
String exPath = options.externExportsPath;
if (!exPath.contains(File.separator)) {
File outputFile = new File(path);
exPath = outputFile.getParent() + File.separatorChar + exPath;
}
return fileNameToOutputWriter(exPath);
}
/**
* Expand a file path specified on the command-line.
*
* Most file paths on the command-line allow an %outname% placeholder.
* The placeholder will expand to a different value depending on
* the current output mode. There are three scenarios:
*
* 1) Single js output, single extra output: sub in jsOutputPath.
* 2) Multiple js output, single extra output: sub in the base module name.
* 3) Multiple js output, multiple extra output: sub in the module output file.
*
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> * Passing a JSModule to this function automatically triggers case #3.
* Otherwise, we'll use strategy #1 or #2 based on the current output mode.
*/
private String expandCommandLinePath(
String path, JSModule forModule) {
String sub;
if (forModule != null) {
sub = config.moduleOutputPathPrefix + forModule.getName() + ".js";
} else if (!config.module.isEmpty()) {
sub = config.moduleOutputPathPrefix;
} else {
sub = config.jsOutputFile;
}
return path.replace("%outname%", sub);
}
/** Expansion function for source map. */
@VisibleForTesting
String expandSourceMapPath(B options, JSModule forModule) {
if (Strings.isEmpty(options.sourceMapOutputPath)) {
return null;
}
return expandCommandLinePath(options.sourceMapOutputPath, forModule);
}
/** Expansion function for the manifest. */
@VisibleForTesting
String expandManifest(JSModule forModule) {
if (Strings.isEmpty(config.outputManifest)) {
return null;
}
return expandCommandLinePath(config.outputManifest, forModule);
}
/**
* Converts a file name into a Writer.
* Returns null if the file name is null.
*/
private Writer fileNameToOutputWriter(String fileName) throws IOException {
if (fileName == null) {
return null;
}
if (testMode) {
return new StringWriter();
}
return streamToOutputWriter(new FileOutputStream(fileName));
}
/**
* Create a writer.
*/
private Writer streamToOutputWriter(OutputStream stream)
throws IOException {
if (outputCharset == null) {
return new BufferedWriter(
new OutputStreamWriter(stream));
} else {
return new BufferedWriter(
new OutputStreamWriter(stream, outputCharset));
}
}
/**
* Outputs the source map found in the compiler to the proper path if one
* exists.
*
* @param options The options to the Compiler.
*/
private void outputSourceMap(B options)
throws IOException {
if (Strings.isEmpty(options.sourceMapOutputPath)) {
return;
}
String outName = expandSourceMapPath(options, null);
Writer out = fileNameToOutput
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>Writer(outName);
compiler.getSourceMap().appendTo(out, outName);
out.close();
}
/**
* Returns the path at which to output map file(s) based on the path at which
* the JS binary will be placed.
*
* @return The path in which to place the generated map file(s).
*/
private String getMapPath(String outputFile) {
String basePath = "";
if (outputFile.equals("")) {
// If we have a js_module_binary rule, output the maps
// at modulename_props_map.out, etc.
if (!config.moduleOutputPathPrefix.equals("")) {
basePath = config.moduleOutputPathPrefix;
} else {
basePath = "jscompiler";
}
} else {
// Get the path of the output file.
File file = new File(outputFile);
String outputFileName = file.getName();
// Strip the .js from the name.
if (outputFileName.endsWith(".js")) {
outputFileName =
outputFileName.substring(0, outputFileName.length() - 3);
}
basePath = file.getParent() + File.separatorChar + outputFileName;
}
return basePath;
}
/**
* Outputs the variable and property name maps for the specified compiler if
* the proper FLAGS are set.
*/
private void outputNameMaps(B options) throws FlagUsageException,
IOException {
String propertyMapOutputPath = null;
String variableMapOutputPath = null;
String functionInformationMapOutputPath = null;
// Check the create_name_map_files FLAG.
if (config.createNameMapFiles) {
String basePath = getMapPath(options.jsOutputFile);
propertyMapOutputPath = basePath + "_props_map.out";
variableMapOutputPath = basePath + "_vars_map.out";
functionInformationMapOutputPath = basePath + "_functions_map.out";
}
// Check the individual FLAGS.
if (!config.variableMapOutputFile.equals("")) {
if (variableMapOutputPath != null) {
throw new FlagUsageException("The flags variable_map_output_file and "
+ "create_name_map_files cannot both be used simultaniously.");
}
variableMapOutputPath = config.variableMapOutputFile;
}
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> if (!config.propertyMapOutputFile.equals("")) {
if (propertyMapOutputPath != null) {
throw new FlagUsageException("The flags property_map_output_file and "
+ "create_name_map_files cannot both be used simultaniously.");
}
propertyMapOutputPath = config.propertyMapOutputFile;
}
// Output the maps.
if (variableMapOutputPath != null) {
if (compiler.getVariableMap() != null) {
compiler.getVariableMap().save(variableMapOutputPath);
}
}
if (propertyMapOutputPath != null) {
if (compiler.getPropertyMap() != null) {
compiler.getPropertyMap().save(propertyMapOutputPath);
}
}
if (functionInformationMapOutputPath != null) {
if (compiler.getFunctionalInformationMap() != null) {
FileOutputStream file =
new FileOutputStream(functionInformationMapOutputPath);
CodedOutputStream outputStream = CodedOutputStream.newInstance(file);
compiler.getFunctionalInformationMap().writeTo(outputStream);
outputStream.flush();
file.flush();
file.close();
}
}
}
/**
* Create a map of constant names to constant values from a textual
* description of the map.
*
* @param definitions A list of overriding definitions for defines in
* the form <name>[=<val>], where <val> is a number, boolean, or
* single-quoted string without single quotes.
*/
@VisibleForTesting
static void createDefineReplacements(List<String> definitions,
CompilerOptions options) {
// Parse the definitions
for (String override : definitions) {
String[] assignment = override.split("=", 2);
String defName = assignment[0];
if (defName.length() > 0) {
if (assignment.length == 1) {
options.setDefineToBooleanLiteral(defName, true);
continue;
} else {
String defValue = assignment[1];
if (defValue.equals("true")) {
options.setDefineToBooleanLiteral(defName, true);
continue;
} else if (defValue.equals("false")) {
options.setDefineToBooleanLiteral(defName, false);
continue;
} else if (defValue.length() >
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> 1
&& ((defValue.charAt(0) == '\'' &&
defValue.charAt(defValue.length() - 1) == '\'')
|| (defValue.charAt(0) == '\"' &&
defValue.charAt(defValue.length() - 1) == '\"'))) {
// If the value starts and ends with a single quote,
// we assume that it's a string.
String maybeStringVal =
defValue.substring(1, defValue.length() - 1);
if (maybeStringVal.indexOf(defValue.charAt(0)) == -1) {
options.setDefineToStringLiteral(defName, maybeStringVal);
continue;
}
} else {
try {
options.setDefineToDoubleLiteral(defName,
Double.parseDouble(defValue));
continue;
} catch (NumberFormatException e) {
// do nothing, it will be caught at the end
}
}
}
}
throw new RuntimeException(
"--define flag syntax invalid: " + override);
}
}
/**
* Returns true if and only if a manifest should be generated for each
* module, as opposed to one unified manifest.
*/
private boolean shouldGenerateManifestPerModule() {
return !config.module.isEmpty()
&& config.outputManifest != null
&& config.outputManifest.contains("%outname%");
}
/**
* Writes the manifest of all compiler input files that survived
* manage_closure_dependencies, if requested.
*/
private void outputManifest() throws IOException {
String outputManifest = config.outputManifest;
if (Strings.isEmpty(outputManifest)) {
return;
}
JSModuleGraph graph = compiler.getModuleGraph();
if (shouldGenerateManifestPerModule()) {
// Generate per-module manifests.
Iterable<JSModule> modules = graph.getAllModules();
for (JSModule module : modules) {
Writer out = fileNameToOutputWriter(expandManifest(module));
printManifestTo(module.getInputs(), out);
out.close();
}
} else {
// Generate a single file manifest.
Writer out = fileNameToOutputWriter(expandManifest(null));
if (graph == null) {
printManifestTo(compiler.getInputsInOrder(), out);
} else {
printModuleGraphManifest
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> visit(NodeTraversal t, Node n, Node parent) {
if (n.getType() == Token.CALL &&
GET_CSS_NAME_FUNCTION.equals(n.getFirstChild().getQualifiedName())) {
int count = n.getChildCount();
Node first = n.getFirstChild().getNext();
switch (count) {
case 2:
// Replace the function call with the processed argument.
if (first.getType() == Token.STRING) {
processStringNode(t, first);
n.removeChild(first);
parent.replaceChild(n, first);
compiler.reportCodeChange();
} else {
compiler.report(t.makeError(n, STRING_LITERAL_EXPECTED_ERROR,
Token.name(first.getType())));
}
break;
case 3:
// Replace function call with concatenation of two args. It's
// assumed the first arg has already been processed.
Node second = first.getNext();
if (first.getType() == Token.STRING) {
compiler.report(t.makeError(
n, UNEXPECTED_STRING_LITERAL_ERROR,
first.getString(), second.getString()));
} else if (second.getType() == Token.STRING) {
processStringNode(t, second);
n.removeChild(first);
Node replacement = new Node(Token.ADD, first,
Node.newString("-" + second.getString())
.copyInformationFrom(second))
.copyInformationFrom(n);
replacement.setJSType(nativeStringType);
parent.replaceChild(n, replacement);
compiler.reportCodeChange();
} else {
compiler.report(t.makeError(n, STRING_LITERAL_EXPECTED_ERROR,
Token.name(second.getType())));
}
break;
default:
compiler.report(t.makeError(
n, INVALID_NUM_ARGUMENTS_ERROR, String.valueOf(count)));
}
}
}
/**
* Processes a string argument to goog.getCssName(). The string will be
* renamed based off the symbol map. If there is no map or any part of the
* name can't be renamed, a warning is reported to the compiler and the node
* is left unchanged.
*
* If the type is unexpected then an error is reported to the
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> compiler.
*
* @param t The node traversal.
* @param n The string node to process.
*/
private void processStringNode(NodeTraversal t, Node n) {
if (symbolMap != null || cssNames != null) {
String[] parts = n.getString().split("-");
for (int i = 0; i < parts.length; i++) {
if (cssNames != null) {
Integer count = cssNames.get(parts[i]);
if (count == null) {
count = Integer.valueOf(0);
}
cssNames.put(parts[i], count.intValue() + 1);
}
if (symbolMap != null) {
String replacement = symbolMap.get(parts[i]);
if (replacement == null) {
// If we can't encode all parts, don't encode any of it.
compiler.report(t.makeError(
n, UNKNOWN_SYMBOL_WARNING, parts[i], n.getString()));
return;
}
parts[i] = replacement;
}
}
if (symbolMap != null) {
n.setString(Joiner.on("-").join(parts));
}
}
}
}
}
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> null;
if (callName.getType() == Token.GETPROP) {
methodName = callName.getLastChild().getString();
} else if (callName.getType() == Token.NAME) {
String name = callName.getString();
int dollarIndex = name.lastIndexOf('$');
if (dollarIndex != -1) {
methodName = name.substring(dollarIndex + 1);
}
}
if (methodName != null) {
if (methodName.equals("inherits")) {
return SubclassType.INHERITS;
} else if (methodName.equals("mixin")) {
return SubclassType.MIXIN;
}
}
return null;
}
@Override
public boolean isSuperClassReference(String propertyName) {
return "superClass_".equals(propertyName);
}
/**
* Given a qualified name node, strip "prototype" off the end.
*
* Examples of this transformation:
* a.b.c => a.b.c
* a.b.c.prototype => a.b.c
*/
private Node stripPrototype(Node qualifiedName) {
if (qualifiedName.getType() == Token.GETPROP &&
qualifiedName.getLastChild().getString().equals("prototype")) {
return qualifiedName.getFirstChild();
}
return qualifiedName;
}
/**
* Exctracts X from goog.provide('X'), if the applied Node is goog.
*
* @return The extracted class name, or null.
*/
@Override
public String extractClassNameIfProvide(Node node, Node parent){
return extractClassNameIfGoog(node, parent, "goog.provide");
}
/**
* Exctracts X from goog.require('X'), if the applied Node is goog.
*
* @return The extracted class name, or null.
*/
@Override
public String extractClassNameIfRequire(Node node, Node parent){
return extractClassNameIfGoog(node, parent, "goog.require");
}
private static String extractClassNameIfGoog(Node node, Node parent,
String functionName){
String className = null;
if (NodeUtil.isExprCall(parent)) {
Node callee = node.getFirstChild();
if (callee != null && callee.getType() == Token.GETPROP) {
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>
String qualifiedName = callee.getQualifiedName();
if ((functionName).equals(qualifiedName)) {
className = callee.getNext().getString();
}
}
}
return className;
}
/**
* Use closure's implementation.
* @return closure's function name for exporting properties.
*/
@Override
public String getExportPropertyFunction() {
return "goog.exportProperty";
}
/**
* Use closure's implementation.
* @return closure's function name for exporting symbols.
*/
@Override
public String getExportSymbolFunction() {
return "goog.exportSymbol";
}
@Override
public List<String> identifyTypeDeclarationCall(Node n) {
Node callName = n.getFirstChild();
if ("goog.addDependency".equals(callName.getQualifiedName()) &&
n.getChildCount() >= 3) {
Node typeArray = callName.getNext().getNext();
if (typeArray.getType() == Token.ARRAYLIT) {
List<String> typeNames = Lists.newArrayList();
for (Node name = typeArray.getFirstChild(); name != null;
name = name.getNext()) {
if (name.getType() == Token.STRING) {
typeNames.add(name.getString());
}
}
return typeNames;
}
}
return null;
}
@Override
public String identifyTypeDefAssign(Node n) {
Node firstChild = n.getFirstChild();
int type = n.getType();
if (type == Token.ASSIGN) {
if (TYPEDEF_NAME.equals(n.getLastChild().getQualifiedName())) {
return firstChild.getQualifiedName();
}
} else if (type == Token.VAR && firstChild.hasChildren()) {
if (TYPEDEF_NAME.equals(
firstChild.getFirstChild().getQualifiedName())) {
return firstChild.getString();
}
}
return null;
}
@Override
public String getAbstractMethodName() {
return "goog.abstractMethod";
}
@Override
public String getSingletonGetterClassName(Node callNode) {
Node callArg = callNode.getFirstChild();
String callName = callArg.getQualifiedName();
// Use both the original name and the post-CollapseProperties name.
if (!("goog.addSingletonGetter".equals(callName
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>_call";
default:
Kit.codeBug();
}
return null;
}
private static class NumberNode extends Node {
private static final long serialVersionUID = 1L;
NumberNode(double number) {
super(Token.NUMBER);
this.number = number;
}
public NumberNode(double number, int lineno, int charno) {
super(Token.NUMBER, lineno, charno);
this.number = number;
}
@Override
public double getDouble() {
return this.number;
}
@Override
public void setDouble(double d) {
this.number = d;
}
@Override
public boolean isEquivalentTo(Node node) {
return (node instanceof NumberNode
&& getDouble() == ((NumberNode) node).getDouble());
}
private double number;
}
private static class StringNode extends Node {
private static final long serialVersionUID = 1L;
StringNode(int type, String str) {
super(type);
if (null == str) {
throw new IllegalArgumentException("StringNode: str is null");
}
this.str = str;
}
StringNode(int type, String str, int lineno, int charno) {
super(type, lineno, charno);
if (null == str) {
throw new IllegalArgumentException("StringNode: str is null");
}
this.str = str;
}
/**
* returns the string content.
* @return non null.
*/
@Override
public String getString() {
return this.str;
}
/**
* sets the string content.
* @param str the new value. Non null.
*/
@Override
public void setString(String str) {
if (null == str) {
throw new IllegalArgumentException("StringNode: str is null");
}
this.str = str;
}
@Override
public boolean isEquivalentTo(Node node) {
return (node instanceof StringNode &&
this.str.equals(((StringNode) node).str));
}
/**
* If the property is not defined, this was not a quoted key. The
* QUOTED_PROP int property is only assigned to STRING tokens used as
* object lit keys.
* @return true if this was a quoted string key in an
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>Type, int value) {
removeProp(propType);
if (value != 0) {
propListHead = new PropListItem(propType, value, propListHead);
}
}
// Gets all the property types, in sorted order.
private int[] getSortedPropTypes() {
int count = 0;
for (PropListItem x = propListHead; x != null; x = x.next) {
count++;
}
int[] keys = new int[count];
for (PropListItem x = propListHead; x != null; x = x.next) {
count--;
keys[count] = x.type;
}
Arrays.sort(keys);
return keys;
}
public int getLineno() {
return extractLineno(sourcePosition);
}
public int getCharno() {
return extractCharno(sourcePosition);
}
/** Can only be called when <tt>getType() == TokenStream.NUMBER</tt> */
public double getDouble() throws UnsupportedOperationException {
if (this.getType() == Token.NUMBER) {
throw new IllegalStateException(
"Number node not created with Node.newNumber");
} else {
throw new UnsupportedOperationException(this + " is not a number node");
}
}
/** Can only be called when <tt>getType() == TokenStream.NUMBER</tt> */
public void setDouble(double s) throws UnsupportedOperationException {
if (this.getType() == Token.NUMBER) {
throw new IllegalStateException(
"Number node not created with Node.newNumber");
} else {
throw new UnsupportedOperationException(this + " is not a string node");
}
}
/** Can only be called when node has String context. */
public String getString() throws UnsupportedOperationException {
if (this.getType() == Token.STRING) {
throw new IllegalStateException(
"String node not created with Node.newString");
} else {
throw new UnsupportedOperationException(this + " is not a string node");
}
}
/** Can only be called when node has String context. */
public void setString(String s) throws UnsupportedOperationException {
if (this.getType() == Token.STRING) {
throw new IllegalStateException(
"String node not created with Node.newString");
} else {
throw new UnsupportedOperationException(this + " is not a string node
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>");
}
}
@Override
public String toString() {
return toString(true, true, true);
}
public String toString(
boolean printSource,
boolean printAnnotations,
boolean printType) {
if (Token.printTrees) {
StringBuilder sb = new StringBuilder();
toString(sb, printSource, printAnnotations, printType);
return sb.toString();
}
return String.valueOf(type);
}
private void toString(
StringBuilder sb,
boolean printSource,
boolean printAnnotations,
boolean printType) {
if (Token.printTrees) {
sb.append(Token.name(type));
if (this instanceof StringNode) {
sb.append(' ');
sb.append(getString());
} else if (type == Token.FUNCTION) {
sb.append(' ');
// In the case of JsDoc trees, the first child is often not a string
// which causes exceptions to be thrown when calling toString or
// toStringTree.
if (first.getType() == Token.STRING) {
sb.append(first.getString());
}
} else if (this instanceof ScriptOrFnNode) {
ScriptOrFnNode sof = (ScriptOrFnNode) this;
if (this instanceof FunctionNode) {
FunctionNode fn = (FunctionNode) this;
sb.append(' ');
sb.append(fn.getFunctionName());
}
if (printSource) {
sb.append(" [source name: ");
sb.append(sof.getSourceName());
sb.append("] [encoded source length: ");
sb.append(sof.getEncodedSourceEnd() - sof.getEncodedSourceStart());
sb.append("] [base line: ");
sb.append(sof.getBaseLineno());
sb.append("] [end line: ");
sb.append(sof.getEndLineno());
sb.append(']');
}
} else if (type == Token.NUMBER) {
sb.append(' ');
sb.append(getDouble());
}
if (printSource) {
int lineno = getLineno();
if (lineno != -1) {
sb.append(' ');
sb.append(lineno);
}
}
if (printAnnotations) {
int[] keys = getSortedPropTypes();
for (int i =
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>.BREAK:
case Token.CONTINUE:
case Token.VAR:
case Token.CONST:
case Token.WITH:
case Token.CATCH:
case Token.FINALLY:
case Token.BLOCK:
case Token.LABEL:
case Token.TARGET:
case Token.LOOP:
case Token.JSR:
case Token.SETPROP_OP:
case Token.SETELEM_OP:
case Token.LOCAL_BLOCK:
case Token.SET_REF_OP:
return true;
default:
return false;
}
}
/**
* This function takes a set of GETPROP nodes and produces a string that is
* each property separated by dots. If the node ultimately under the left
* sub-tree is not a simple name, this is not a valid qualified name.
*
* @return a null if this is not a qualified name, or a dot-separated string
* of the name and properties.
*/
public String getQualifiedName() {
if (type == Token.NAME) {
return getString();
} else if (type == Token.GETPROP) {
String left = getFirstChild().getQualifiedName();
if (left == null) {
return null;
}
return left + "." + getLastChild().getString();
} else if (type == Token.THIS) {
return "this";
} else {
return null;
}
}
/**
* Returns whether a node corresponds to a simple or a qualified name, such as
* <code>x</code> or <code>a.b.c</code> or <code>this.a</code>.
*/
public boolean isQualifiedName() {
switch (getType()) {
case Token.NAME:
case Token.THIS:
return true;
case Token.GETPROP:
return getFirstChild().isQualifiedName();
default:
return false;
}
}
/**
* Returns whether a node corresponds to a simple or a qualified name without
* a "this" reference, such as <code>a.b.c</code>, but not <code>this.a</code>
* .
*/
public boolean isUnscopedQualifiedName() {
switch (getType()) {
case Token.NAME:
return true;
case Token.GETPROP:
return getFirstChild().is
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> attempt to replace the arguments. The currentArgumentsAccess
// is stale and as we exit the Scope, no longer holds all the access to the
// current scope anymore. We'll pop the access list from the outer scope
// and set it as currentArgumentsAcess if the outer scope is not the global
// scope.
if (!argumentsAccessStack.isEmpty()) {
currentArgumentsAccess = argumentsAccessStack.pop();
} else {
currentArgumentsAccess = null;
}
}
@Override
public boolean shouldTraverse(
NodeTraversal nodeTraversal, Node node, Node parent) {
// We will continuously recurse down the AST regardless of the node types.
return true;
}
@Override
public void visit(NodeTraversal traversal, Node node, Node parent) {
Preconditions.checkNotNull(traversal);
Preconditions.checkNotNull(node);
// Searches for all the references to the arguments array.
// We don't have an arguments list set up for this scope. This implies we
// are currently in the global scope so we will not record any arguments
// array access.
if (currentArgumentsAccess == null) {
return;
}
// Otherwise, we are in a function scope and we should record if the current
// name is referring to the implicit arguments array.
if (NodeUtil.isName(node) && ARGUMENTS.equals(node.getString())) {
currentArgumentsAccess.add(node);
}
}
/**
* Tries to optimize all the arguments array access in this scope by assigning
* a name to each element.
*
* @param scope scope of the function
* @return true if any modification has been done to the AST
*/
private boolean tryReplaceArguments(Scope scope) {
Node parametersList = scope.getRootNode().getFirstChild().getNext();
Preconditions.checkState(parametersList.getType() == Token.LP);
// Keep track of rather this function modified the AST and needs to be
// reported back to the compiler later.
boolean changed = false;
// Number of parameter that can be accessed without using the arguments
// array.
int numNamedParameter = parametersList.getChildCount();
// We want to guess what the highest index that has been access from the
// arguments array. We will guess that it does not use anything index higher
// than the named parameter list first until we see
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> the formal parameter to the method's signature.
// Example: function() --> function(r0, r1, r2)
for (int i = 0; i < numExtraArgs; i++) {
String name = getNewName();
argNames[i] = name;
parametersList.addChildrenToBack(Node.newString(Token.NAME, name));
changed = true;
}
// This loop performs the replacement of arguments[x] -> a if x is known.
for (Node ref : currentArgumentsAccess) {
Node index = ref.getNext();
// Skip if it is unknown.
if (index.getType() != Token.NUMBER) {
continue;
}
int value = (int) index.getDouble();
// Unnamed parameter.
if (value >= numNamedParameter) {
ref.getParent().getParent().replaceChild(ref.getParent(),
Node.newString(Token.NAME, argNames[value - numNamedParameter]));
} else {
// Here, for no apparent reason, the user is accessing a named parameter
// with arguments[idx]. We can replace it with the actual name for them.
Node name = parametersList.getFirstChild();
// This is a linear search for the actual name from the signature.
// It is not necessary to make this fast because chances are the user
// will not deliberately write code like this.
for (int i = 0; i < value; i++) {
name = name.getNext();
}
ref.getParent().getParent().replaceChild(ref.getParent(),
Node.newString(Token.NAME, name.getString()));
}
changed = true;
}
return changed;
}
/**
* Generate a unique name for the next parameter.
*/
private String getNewName() {
return paramPredix + uniqueId++;
}
}
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> node.getFirstChild();
// Function declarations are skipped since control doesn't go into that
// function (unless it is called)
while (child != null && child.getType() == Token.FUNCTION) {
child = child.getNext();
}
if (child != null) {
createEdge(node, Branch.UNCOND, computeFallThrough(child));
} else {
createEdge(node, Branch.UNCOND, computeFollowNode(node, this));
}
// Synthetic blocks
if (parent != null) {
switch (parent.getType()) {
case Token.DEFAULT:
case Token.CASE:
case Token.TRY:
break;
default:
if (node.getType() == Token.BLOCK && node.isSyntheticBlock()) {
createEdge(node, Branch.SYN_BLOCK, computeFollowNode(node, this));
}
break;
}
}
}
private void handleFunction(Node node) {
// A block transfer control to its first child if it is not empty.
Preconditions.checkState(node.getChildCount() >= 3);
createEdge(node, Branch.UNCOND,
computeFallThrough(node.getFirstChild().getNext().getNext()));
Preconditions.checkState(exceptionHandler.peek() == node);
exceptionHandler.pop();
}
private void handleExpr(Node node) {
createEdge(node, Branch.UNCOND, computeFollowNode(node, this));
connectToPossibleExceptionHandler(node, node);
}
private void handleThrow(Node node) {
connectToPossibleExceptionHandler(node, node);
}
private void handleTry(Node node) {
createEdge(node, Branch.UNCOND, node.getFirstChild());
}
private void handleCatch(Node node) {
createEdge(node, Branch.UNCOND, node.getLastChild());
}
private void handleBreak(Node node) {
String label = null;
// See if it is a break with label.
if (node.hasChildren()) {
label = node.getFirstChild().getString();
}
Node cur;
Node lastJump;
Node parent = node.getParent();
/*
* Continuously look up the ancestor tree for the BREAK target or the target
* with the corresponding label and connect to it. If along the path we
* discover
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> a FINALLY, we will connect the BREAK to that FINALLY. From then
* on, we will just record the control flow changes in the finallyMap. This
* is due to the fact that we need to connect any node that leaves its own
* FINALLY block to the outer FINALLY or the BREAK's target but those nodes
* are not known yet due to the way we traverse the nodes.
*/
for (cur = node, lastJump = node;
!isBreakTarget(cur, label);
cur = parent, parent = parent.getParent()) {
if (cur.getType() == Token.TRY && NodeUtil.hasFinally(cur)) {
if (lastJump == node) {
createEdge(lastJump, Branch.UNCOND, computeFallThrough(
cur.getLastChild()));
} else {
finallyMap.put(lastJump, computeFallThrough(cur.getLastChild()));
}
lastJump = cur;
}
Preconditions.checkState(parent != null, "Cannot find break target.");
}
if (lastJump == node) {
createEdge(lastJump, Branch.UNCOND, computeFollowNode(cur, this));
} else {
finallyMap.put(lastJump, computeFollowNode(cur, this));
}
}
private void handleContinue(Node node) {
String label = null;
if (node.hasChildren()) {
label = node.getFirstChild().getString();
}
Node cur;
Node lastJump;
// Similar to handBreak's logic with a few minor variation.
Node parent = node.getParent();
for (cur = node, lastJump = node;
!isContinueTarget(cur, parent, label);
cur = parent, parent = parent.getParent()) {
if (cur.getType() == Token.TRY && NodeUtil.hasFinally(cur)) {
if (lastJump == node) {
createEdge(lastJump, Branch.UNCOND, cur.getLastChild());
} else {
finallyMap.put(lastJump, computeFallThrough(cur.getLastChild()));
}
lastJump = cur;
}
Preconditions.checkState(parent != null, "Cannot find continue target.");
}
Node iter = cur;
if (cur.getChildCount() == 4) {
iter = cur.getFirstChild().getNext().
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> the continue target of labeled continue. The
* label can be null if it is an unlabeled continue.
*/
private static boolean isContinueTarget(
Node target, Node parent, String label) {
return isContinueStructure(target) && matchLabel(parent, label);
}
/**
* Check if label is actually referencing the target control structure. If
* label is null, it always returns true.
*/
private static boolean matchLabel(Node target, String label) {
if (label == null) {
return true;
}
while (target.getType() == Token.LABEL) {
if (target.getFirstChild().getString().equals(label)) {
return true;
}
target = target.getParent();
}
return false;
}
/**
* Determines if the subtree might throw an exception.
*/
public static boolean mayThrowException(Node n) {
switch (n.getType()) {
case Token.CALL:
case Token.GETPROP:
case Token.GETELEM:
case Token.THROW:
case Token.NEW:
case Token.ASSIGN:
case Token.INC:
case Token.DEC:
case Token.INSTANCEOF:
return true;
case Token.FUNCTION:
return false;
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(c) && mayThrowException(c)) {
return true;
}
}
return false;
}
/**
* Determines whether the given node can be terminated with a BREAK node.
*/
static boolean isBreakStructure(Node n, boolean labeled) {
switch (n.getType()) {
case Token.FOR:
case Token.DO:
case Token.WHILE:
case Token.SWITCH:
return true;
case Token.BLOCK:
case Token.IF:
case Token.TRY:
return labeled;
default:
return false;
}
}
/**
* Determines whether the given node can be advanced with a CONTINUE node.
*/
static boolean isContinueStructure(Node n) {
switch (n.getType()) {
case Token.FOR:
case Token.DO:
case Token.WHILE:
return true;
default:
return false;
}
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>hasChildren()) {
tryRemoveAssignment(t, n.getFirstChild(), state);
}
continue;
// TODO(user): case Token.VAR: Remove var a=1;a=2;.....
}
tryRemoveAssignment(t, n, state);
}
}
private void tryRemoveAssignment(NodeTraversal t, Node n,
FlowState<LiveVariableLattice> state) {
tryRemoveAssignment(t, n, n, state);
}
/**
* Determines if any local variables are dead after the instruction {@code n}
* and are assigned within the subtree of {@code n}. Removes those assignments
* if there are any.
*
* @param n Target instruction.
* @param exprRoot The CFG node where the liveness information in state is
* still correct.
* @param state The liveness information at {@code n}.
*/
private void tryRemoveAssignment(NodeTraversal t, Node n, Node exprRoot,
FlowState<LiveVariableLattice> state) {
Node parent = n.getParent();
if (NodeUtil.isAssignmentOp(n) ||
n.getType() == Token.INC || n.getType() == Token.DEC) {
Node lhs = n.getFirstChild();
Node rhs = lhs.getNext();
// Recurse first. Example: dead_x = dead_y = 1; We try to clean up dead_y
// first.
if (rhs != null) {
tryRemoveAssignment(t, rhs, exprRoot, state);
rhs = lhs.getNext();
}
Scope scope = t.getScope();
if (!NodeUtil.isName(lhs)) {
return; // Not a local variable assignment.
}
String name = lhs.getString();
if (!scope.isDeclared(name, false)) {
return;
}
Var var = scope.getVar(name);
if (liveness.getEscapedLocals().contains(var)) {
return; // Local variable that might be escaped due to closures.
}
// If we have an identity assignment such as a=a, always remove it
// regardless of what the liveness results because it
// does not change the result afterward.
if (rhs != null &&
NodeUtil.isName(rhs) &&
rhs
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>.getString().equals(var.name) &&
NodeUtil.isAssign(n)) {
n.removeChild(rhs);
n.getParent().replaceChild(n, rhs);
compiler.reportCodeChange();
return;
}
if (state.getOut().isLive(var)) {
return; // Variable not dead.
}
if (state.getIn().isLive(var) &&
isVariableStillLiveWithinExpression(n, exprRoot, var.name)) {
// The variable is killed here but it is also live before it.
// This is possible if we have say:
// if (X = a && a = C) {..} ; .......; a = S;
// In this case we are safe to remove "a = C" because it is dead.
// However if we have:
// if (a = C && X = a) {..} ; .......; a = S;
// removing "a = C" is NOT correct, although the live set at the node
// is exactly the same.
// TODO(user): We need more fine grain CFA or we need to keep track
// of GEN sets when we recurse here.
return;
}
if (NodeUtil.isAssign(n)) {
n.removeChild(rhs);
n.getParent().replaceChild(n, rhs);
} else if (NodeUtil.isAssignmentOp(n)) {
n.removeChild(rhs);
n.removeChild(lhs);
Node op = new Node(NodeUtil.getOpFromAssignmentOp(n), lhs, rhs);
parent.replaceChild(n, op);
} else if (n.getType() == Token.INC || n.getType() == Token.DEC) {
if (NodeUtil.isExpressionNode(parent)) {
parent.replaceChild(n,
new Node(Token.VOID, Node.newNumber(0).copyInformationFrom(n)));
} else if(n.getType() == Token.COMMA && n != parent.getLastChild()) {
parent.removeChild(n);
} else if (parent.getType() == Token.FOR && !NodeUtil.isForIn(parent) &&
NodeUtil.getConditionExpression(parent) != n) {
parent.replaceChild(n, new Node(Token.EMPTY));
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>
MAYBE_LIVE, // May be still live in the current expression tree.
READ, // Known there is a read left of it.
KILL, // Known there is a write before any read.
}
/**
* Give an expression and a variable. It returns READ, if the right-most
* reference of that variable is a read. It returns KILL, if the right-most
* reference of that variable is an assignment. It returns MAY_LIVE otherwise.
*
* This need to be a pre-order traversal so we cannot use the normal node
* traversals.
*/
private VariableLiveness readVariableBeforeKilling(Node n, String variable) {
if (NodeUtil.isName(n) && variable.equals(n.getString())) {
if (NodeUtil.isLhs(n, n.getParent())) {
return VariableLiveness.KILL;
} else {
return VariableLiveness.READ;
}
}
for (Node child = n.getFirstChild();
child != null; child = child.getNext()) {
if (!ControlFlowGraph.isEnteringNewCfgNode(child)) {
VariableLiveness state = readVariableBeforeKilling(child, variable);
if (state != VariableLiveness.MAYBE_LIVE) {
return state;
}
}
}
return VariableLiveness.MAYBE_LIVE;
}
}
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>(ALL_TYPE);
case Token.LB: // Array type
// TODO(nicksantos): Enforce membership restrictions on the Array.
return getNativeType(ARRAY_TYPE);
case Token.PIPE: // Union type
UnionTypeBuilder builder = new UnionTypeBuilder(this);
for (Node child = n.getFirstChild(); child != null;
child = child.getNext()) {
builder.addAlternate(
createFromTypeNodesInternal(child, sourceName, scope, false));
}
return builder.build();
case Token.EMPTY: // When the return value of a function is not specified
return getNativeType(UNKNOWN_TYPE);
case Token.VOID: // Only allowed in the return value of a function.
return getNativeType(VOID_TYPE);
case Token.STRING:
JSType namedType = getType(scope, n.getString(), sourceName,
n.getLineno(), n.getCharno());
if (forgiving) {
namedType.forgiveUnknownNames();
}
if (resolveMode != ResolveMode.LAZY_NAMES) {
namedType = namedType.resolveInternal(reporter, scope);
}
if ((namedType instanceof ObjectType) &&
!(enumTypeNames.contains(n.getString()))) {
Node typeList = n.getFirstChild();
if (typeList != null &&
("Array".equals(n.getString()) ||
"Object".equals(n.getString()))) {
JSType parameterType =
createFromTypeNodesInternal(
typeList.getLastChild(), sourceName, scope, false);
namedType = new ParameterizedType(
this, (ObjectType) namedType, parameterType);
if (typeList.hasMoreThanOneChild()) {
JSType indexType =
createFromTypeNodesInternal(
typeList.getFirstChild(), sourceName, scope, false);
namedType = new IndexedType(
this, (ObjectType) namedType, indexType);
}
}
return createDefaultObjectUnion(namedType);
} else {
return namedType;
}
case Token.FUNCTION:
ObjectType thisType = null;
Node current = n.getFirstChild();
if (current.getType() == Token.THIS) {
Node thisNode = current.getFirstChild();
thisType =
ObjectType.cast(
createFromTypeNodes
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> scope) {
RecordTypeBuilder builder = new RecordTypeBuilder(this);
// For each of the fields in the record type.
for (Node fieldTypeNode = n.getFirstChild();
fieldTypeNode != null;
fieldTypeNode = fieldTypeNode.getNext()) {
// Get the property's name.
Node fieldNameNode = fieldTypeNode;
boolean hasType = false;
if (fieldTypeNode.getType() == Token.COLON) {
fieldNameNode = fieldTypeNode.getFirstChild();
hasType = true;
}
String fieldName = fieldNameNode.getString();
// TODO(user): Move this into the lexer/parser.
// Remove the string literal characters around a field name,
// if any.
if (fieldName.startsWith("'") || fieldName.startsWith("\"")) {
fieldName = fieldName.substring(1, fieldName.length() - 1);
}
// Get the property's type.
JSType fieldType = null;
if (hasType) {
// We have a declared type.
fieldType = createFromTypeNodesInternal(
fieldTypeNode.getLastChild(), sourceName, scope, false);
} else {
// Otherwise, the type is UNKNOWN.
fieldType = getNativeType(JSTypeNative.UNKNOWN_TYPE);
}
// Add the property to the record.
builder.addProperty(fieldName, fieldType);
}
return builder.build();
}
/**
* Sets the template type name.
*/
public void setTemplateTypeName(String name) {
templateTypeName = name;
templateType = new TemplateType(this, name);
}
/**
* Clears the template type name.
*/
public void clearTemplateTypeName() {
templateTypeName = null;
templateType = null;
}
}
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>
}
return false;
}
/**
* Records a throw type's description.
*
* @return {@code true} if the type's description was recorded and
* {@code false} if a description with the same type was already defined
*/
public boolean recordThrowDescription(JSTypeExpression type, String description) {
if (currentInfo.documentThrows(type, description)) {
populated = true;
return true;
} else {
return false;
}
}
/**
* Adds an author to the current information.
*/
public boolean addAuthor(String author) {
if (currentInfo.documentAuthor(author)) {
populated = true;
return true;
} else {
return false;
}
}
/**
* Adds a reference ("@see") to the current information.
*/
public boolean addReference(String reference) {
if (currentInfo.documentReference(reference)) {
populated = true;
return true;
} else {
return false;
}
}
/**
* Records the version.
*/
public boolean recordVersion(String version) {
if (currentInfo.documentVersion(version)) {
populated = true;
return true;
} else {
return false;
}
}
/**
* Records the deprecation reason.
*/
public boolean recordDeprecationReason(String reason) {
if (currentInfo.setDeprecationReason(reason)) {
populated = true;
return true;
} else {
return false;
}
}
/**
* Records the list of suppressed warnings.
*/
public boolean recordSuppressions(Set<String> suppressions) {
if (currentInfo.setSuppressions(suppressions)) {
populated = true;
return true;
} else {
return false;
}
}
/**
* Records a type.
*
* @return {@code true} if the type was recorded and {@code false} if
* it is invalid or was already defined
*/
public boolean recordType(JSTypeExpression type) {
if (type != null && !hasAnyTypeRelatedTags()) {
currentInfo.setType(type);
populated = true;
return true;
} else {
return false;
}
}
/**
* Records that the {@link JSDoc
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>util.Map;
import java.util.Set;
/**
* <p>JSDoc information describing JavaScript code. JSDoc is represented as a
* unified object with fields for each JSDoc annotation, even though some
* combinations are incorrect. For instance, if a JSDoc describes an enum,
* it cannot have information about a return type. This implementation
* takes advantage of such incompatibilities to reuse fields for multiple
* purposes, reducing memory consumption.</p>
*
* <p>Constructing {@link JSDocInfo} objects is simplified by
* {@link JSDocInfoBuilder} which provides early incompatibility detection.</p>
*
*/
public final class JSDocInfo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* Visibility categories. The {@link Visibility#ordinal()} can be used as a
* numerical indicator of privacy, where 0 is the most private. This means
* that the {@link Visibility#compareTo} method can be used to
* determine if a visibility is more permissive than another.
*/
public enum Visibility {
PRIVATE,
PROTECTED,
PUBLIC,
// If visibility is not specified, we just assume that visibility
// is inherited from the super class.
INHERITED
}
private static final class LazilyInitializedInfo implements Serializable {
private static final long serialVersionUID = 1L;
// Function information
JSTypeExpression baseType = null;
List<JSTypeExpression> implementedInterfaces = null;
Map<String, JSTypeExpression> parameters = null;
List<JSTypeExpression> thrownTypes = null;
String templateTypeName = null;
// Other information
String description = null;
String meaning = null;
String deprecated = null;
String license = null;
Set<String> suppressions = null;
}
private static final class LazilyInitializedDocumentation {
// TODO(nicksantos): Use UIntProps to clean up all of this. It takes
// care of all the lazy-instantiation internally.
List<Marker> markers = null;
Map<String, String> parameters = null;
Map<JSTypeExpression, String> throwsDescriptions = null;
String blockDescription = null;
String fileOverview = null;
String returnDescription = null;
String version = null;
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>markers.add(marker);
return marker;
}
/**
* Sets the deprecation reason.
*
* @param reason The deprecation reason
*/
boolean setDeprecationReason(String reason) {
lazyInitInfo();
if (info.deprecated != null) {
return false;
}
info.deprecated = reason;
return true;
}
/**
* Add a suppressed warning.
*/
void addSuppression(String suppression) {
lazyInitInfo();
if (info.suppressions == null) {
info.suppressions = Sets.newHashSet();
}
info.suppressions.add(suppression);
}
/**
* Sets suppressed warnings.
* @param suppressions A list of suppressed warning types.
*/
boolean setSuppressions(Set<String> suppressions) {
lazyInitInfo();
if (info.suppressions != null) {
return false;
}
info.suppressions = suppressions;
return true;
}
/**
* Documents the version.
*/
boolean documentVersion(String version) {
if (!lazyInitDocumentation()) {
return true;
}
if (documentation.version != null) {
return false;
}
documentation.version = version;
return true;
}
/**
* Documents a reference (i.e. adds a "see" reference to the list).
*/
boolean documentReference(String reference) {
if (!lazyInitDocumentation()) {
return true;
}
if (documentation.sees == null) {
documentation.sees = Lists.newArrayList();
}
documentation.sees.add(reference);
return true;
}
/**
* Documents the author (i.e. adds it to the author list).
*/
boolean documentAuthor(String author) {
if (!lazyInitDocumentation()) {
return true;
}
if (documentation.authors == null) {
documentation.authors = Lists.newArrayList();
}
documentation.authors.add(author);
return true;
}
/**
* Documents the throws (i.e. adds it to the throws list).
*/
boolean documentThrows(JSTypeExpression type, String throwsDescription) {
if (!lazyInitDocumentation()) {
return true;
}
if (documentation.throwsDescriptions == null) {
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>);
}
/**
* Returns the list of authors or null if none.
*/
public Collection<String> getAuthors() {
return documentation == null ? null : documentation.authors;
}
/**
* Returns the list of references or null if none.
*/
public Collection<String> getReferences() {
return documentation == null ? null : documentation.sees;
}
/**
* Returns the version or null if none.
*/
public String getVersion() {
return documentation == null ? null : documentation.version;
}
/**
* Returns the description of the returned object or null if none specified.
*/
public String getReturnDescription() {
return documentation == null ? null : documentation.returnDescription;
}
/**
* Returns the block-level description or null if none specified.
*/
public String getBlockDescription() {
return documentation == null ? null : documentation.blockDescription;
}
/**
* Returns whether this has a fileoverview flag.
*/
public boolean hasFileOverview() {
return getFlag(MASK_FILEOVERVIEW);
}
/**
* Returns the file overview or null if none specified.
*/
public String getFileOverview() {
return documentation == null ? null : documentation.fileOverview;
}
/** Gets the name of the source file that contains this JSDoc. */
public String getSourceName() {
return sourceName;
}
/** Gets the list of all markers for the documentation in this JSDoc. */
public Collection<Marker> getMarkers() {
return documentation == null ? null : documentation.markers;
}
/** Sets the name of the source file that contains this JSDoc. */
void setSourceName(String sourceName) {
this.sourceName = sourceName;
}
/** Gets the template type name. */
public String getTemplateTypeName() {
if (info == null) {
return null;
}
return info.templateTypeName;
}
/**
* Returns a collection of all type nodes that are a part of this JSDocInfo.
* This includes @type, @this, @extends, @implements, @param, @throws,
* and @return. Any future type specific JSDoc should make sure to add the
* appropriate nodes here.
* @return collection of all type nodes
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS>GoogNow = rewriteNewDateGoogNow;
// goog is special-cased because it is provided in Closure's base library.
providedNames.put(GOOG,
new ProvidedName(GOOG, null, null, false /* implicit */));
}
Set<String> getExportedVariableNames() {
return exportedVariables;
}
@Override
public void process(Node externs, Node root) {
new NodeTraversal(compiler, this).traverse(root);
for (ProvidedName pn : providedNames.values()) {
pn.replace();
}
if (requiresLevel.isOn()) {
for (UnrecognizedRequire r : unrecognizedRequires) {
DiagnosticType error;
ProvidedName expectedName = providedNames.get(r.namespace);
if (expectedName != null && expectedName.firstNode != null) {
// The namespace ended up getting provided after it was required.
error = LATE_PROVIDE_ERROR;
} else {
error = MISSING_PROVIDE_ERROR;
}
compiler.report(JSError.make(
r.inputName, r.requireNode, requiresLevel, error, r.namespace));
}
}
}
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
switch (n.getType()) {
case Token.CALL:
boolean isExpr = parent.getType() == Token.EXPR_RESULT;
Node left = n.getFirstChild();
if (left.getType() == Token.GETPROP) {
Node name = left.getFirstChild();
if (name.getType() == Token.NAME &&
GOOG.equals(name.getString())) {
// For the sake of simplicity, we report code changes
// when we see a provides/requires, and don't worry about
// reporting the change when we actually do the replacement.
String methodName = name.getNext().getString();
if ("base".equals(methodName)) {
processBaseClassCall(t, n);
} else if (!isExpr) {
// All other methods must be called in an EXPR.
break;
} else if ("require".equals(methodName)) {
processRequireCall(t, n, parent);
} else if ("provide".equals(methodName)) {
processProvideCall(t, n, parent);
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> } else if ("exportSymbol".equals(methodName)) {
Node arg = left.getNext();
if (arg.getType() == Token.STRING) {
int dot = arg.getString().indexOf('.');
if (dot == -1) {
exportedVariables.add(arg.getString());
} else {
exportedVariables.add(arg.getString().substring(0, dot));
}
}
} else if ("addDependency".equals(methodName)) {
CodingConvention convention = compiler.getCodingConvention();
List<String> typeDecls =
convention.identifyTypeDeclarationCall(n);
if (typeDecls != null) {
for (String typeDecl : typeDecls) {
compiler.getTypeRegistry().forwardDeclareType(typeDecl);
}
}
// We can't modify parent, so just create a node that will
// get compiled out.
parent.replaceChild(n, Node.newNumber(0));
compiler.reportCodeChange();
} else if ("setCssNameMapping".equals(methodName)) {
processSetCssNameMapping(t, n, parent);
}
}
}
break;
case Token.ASSIGN:
case Token.NAME:
// If this is an assignment to a provided name, remove the provided
// object.
handleCandidateProvideDefinition(t, n, parent);
break;
case Token.FUNCTION:
// If this is a declaration of a provided named function, this is an
// error. Hosited functions will explode if the're provided.
if (t.inGlobalScope() &&
!NodeUtil.isFunctionExpression(n)) {
String name = n.getFirstChild().getString();
ProvidedName pn = providedNames.get(name);
if (pn != null) {
compiler.report(t.makeError(n, FUNCTION_NAMESPACE_ERROR, name));
}
}
break;
case Token.NEW:
trySimplifyNewDate(t, n, parent);
break;
case Token.GETPROP:
if (n.getFirstChild().getType() == Token.NAME &&
parent.getType() != Token.CALL &&
parent.getType() != Token.ASSIGN &&
"goog.base".equals(n.getQualifiedName())) {
reportBadBaseClassUse(t, n, "May only be called directly.");
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> }
break;
}
}
/**
* Handles a goog.require call.
*/
private void processRequireCall(NodeTraversal t, Node n, Node parent) {
Node left = n.getFirstChild();
Node arg = left.getNext();
if (verifyArgument(t, left, arg)) {
String ns = arg.getString();
ProvidedName provided = providedNames.get(ns);
if (provided == null || !provided.isExplicitlyProvided()) {
unrecognizedRequires.add(
new UnrecognizedRequire(n, ns, t.getSourceName()));
} else {
JSModule providedModule = provided.explicitModule;
// This must be non-null, because there was an explicit provide.
Preconditions.checkNotNull(providedModule);
JSModule module = t.getModule();
if (moduleGraph != null &&
module != providedModule &&
!moduleGraph.dependsOn(module, providedModule)) {
compiler.report(
t.makeError(n, XMODULE_REQUIRE_ERROR, ns,
providedModule.getName(),
module.getName()));
}
}
// Requires should be removed before runtime. The one
// exception is if the type has not been provided yet and
// errors for broken requires are turned off, in which case,
// we will be doing a later pass that may error, so we can
// leave this here this time and let it error next time if it
// is still not provided.
if (provided != null || requiresLevel.isOn()) {
parent.detachFromParent();
compiler.reportCodeChange();
}
}
}
/**
* Handles a goog.provide call.
*/
private void processProvideCall(NodeTraversal t, Node n, Node parent) {
Node left = n.getFirstChild();
Node arg = left.getNext();
if (verifyProvide(t, left, arg)) {
String ns = arg.getString();
if (providedNames.containsKey(ns)) {
ProvidedName previouslyProvided = providedNames.get(ns);
if (!previouslyProvided.isExplicitlyProvided()) {
previouslyProvided.addProvide(parent, t.getModule(), true);
} else {
compiler.report(
t.makeError(n, DUPLICATE_NAMESPACE_ERROR, ns));
}
} else {
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> registerAnyProvidedPrefixes(ns, parent, t.getModule());
providedNames.put(
ns, new ProvidedName(ns, parent, t.getModule(), true));
}
}
}
/**
* Handles a candidate definition for a goog.provided name.
*/
private void handleCandidateProvideDefinition(
NodeTraversal t, Node n, Node parent) {
if (t.inGlobalScope()) {
String name = null;
if (n.getType() == Token.NAME && parent.getType() == Token.VAR) {
name = n.getString();
} else if (n.getType() == Token.ASSIGN &&
parent.getType() == Token.EXPR_RESULT) {
name = n.getFirstChild().getQualifiedName();
}
if (name != null) {
if (parent.getBooleanProp(Node.IS_NAMESPACE)) {
processProvideFromPreviousPass(t, name, parent);
} else {
ProvidedName pn = providedNames.get(name);
if (pn != null) {
pn.addDefinition(parent, t.getModule());
}
}
}
}
}
/**
* Processes the base class call.
*/
private void processBaseClassCall(NodeTraversal t, Node n) {
// Two things must hold for every goog.base call:
// 1) We must be calling it on "this".
// 2) We must be calling it on a prototype method of the same name as
// the one we're in, OR we must be calling it from a constructor.
// If both of those things are true, then we can rewrite:
// <pre>
// function Foo() {
// goog.base(this);
// }
// goog.inherits(Foo, BaseFoo);
// Foo.prototype.bar = function() {
// goog.base(this, 'bar', 1);
// };
// </pre>
// as the easy-to-optimize:
// <pre>
// function Foo() {
// BaseFoo.call(this);
// }
// goog.inherits(Foo, BaseFoo);
// Foo.prototype.bar = function() {
// Foo.superClass_.bar.call(this, 1);
// };
//
// Most of the logic
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> here is just to make sure the AST's
// structure is what we expect it to be.
Node callee = n.getFirstChild();
Node thisArg = callee.getNext();
if (thisArg == null || thisArg.getType() != Token.THIS) {
reportBadBaseClassUse(t, n, "First argument must be 'this'.");
return;
}
Node enclosingFnNameNode = getEnclosingDeclNameNode(t);
if (enclosingFnNameNode == null) {
reportBadBaseClassUse(t, n, "Could not find enclosing method.");
return;
}
String enclosingQname = enclosingFnNameNode.getQualifiedName();
if (enclosingQname.indexOf(".prototype.") == -1) {
// Handle constructors.
Node enclosingParent = enclosingFnNameNode.getParent();
Node maybeInheritsExpr = (enclosingParent.getType() == Token.ASSIGN ?
enclosingParent.getParent() : enclosingParent).getNext();
Node baseClassNode = null;
if (maybeInheritsExpr != null &&
maybeInheritsExpr.getType() == Token.EXPR_RESULT &&
maybeInheritsExpr.getFirstChild().getType() == Token.CALL) {
Node callNode = maybeInheritsExpr.getFirstChild();
if ("goog.inherits".equals(
callNode.getFirstChild().getQualifiedName()) &&
callNode.getLastChild().isQualifiedName()) {
baseClassNode = callNode.getLastChild();
}
}
if (baseClassNode == null) {
reportBadBaseClassUse(
t, n, "Could not find goog.inherits for base class");
return;
}
// We're good to go.
n.replaceChild(
callee,
NodeUtil.newQualifiedNameNode(
String.format("%s.call", baseClassNode.getQualifiedName()),
callee, "goog.base"));
compiler.reportCodeChange();
} else {
// Handle methods.
Node methodNameNode = thisArg.getNext();
if (methodNameNode == null || methodNameNode.getType() != Token.STRING) {
reportBadBaseClassUse(t, n, "Second argument must name a method.");
return;
}
String methodName = methodNameNode.getString();
String ending = ".prototype." +
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> Node expr = new Node(Token.EXPR_RESULT);
expr.copyInformationFromForTree(parent);
parent.getParent().addChildBefore(expr, parent);
compiler.reportCodeChange();
JSModule module = t.getModule();
registerAnyProvidedPrefixes(name, expr, module);
ProvidedName provided = new ProvidedName(name, expr, module, true);
providedNames.put(name, provided);
provided.addDefinition(parent, module);
} else {
// Remove this provide if it came from a previous pass since we have an
// replacement already.
if (isNamespacePlaceholder(parent)) {
parent.getParent().removeChild(parent);
compiler.reportCodeChange();
}
}
}
/**
* Processes a call to goog.setCssNameMapping(). Either the argument to
* goog.setCssNameMapping() is valid, in which case it will be used to create
* a CssRenamingMap for the compiler of this CompilerPass, or it is invalid
* and a JSCompiler error will be reported.
* @see #visit(NodeTraversal, Node, Node)
*/
private void processSetCssNameMapping(NodeTraversal t, Node n, Node parent) {
Node left = n.getFirstChild();
Node arg = left.getNext();
if (verifyArgument(t, left, arg, Token.OBJECTLIT)) {
// Translate OBJECTLIT into SubstitutionMap. All keys and
// values must be strings, or an error will be thrown.
final Map<String, String> cssNames = Maps.newHashMap();
JSError error = null;
for (Node key = arg.getFirstChild(); key != null;
key = key.getNext().getNext()) {
Node value = key.getNext();
if (key.getType() != Token.STRING
|| value == null
|| value.getType() != Token.STRING) {
error = t.makeError(n,
NON_STRING_PASSED_TO_SET_CSS_NAME_MAPPING_ERROR);
}
if (error != null) {
compiler.report(error);
break;
}
cssNames.put(key.getString(), value.getString());
}
// If there were no errors, create a CssRenamingMap from cssNames, update
// the compiler to use it and remove the
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> call to goog.setCssNameMapping().
if (error == null) {
CssRenamingMap cssRenamingMap = new CssRenamingMap() {
public String get(String value) {
if (cssNames.containsKey(value)) {
return cssNames.get(value);
} else {
return value;
}
}
};
compiler.setCssRenamingMap(cssRenamingMap);
parent.getParent().removeChild(parent);
compiler.reportCodeChange();
}
}
}
/**
* Try to simplify "new Date(goog.now())" to "new Date()".
*/
private void trySimplifyNewDate(NodeTraversal t, Node n, Node parent) {
if (!rewriteNewDateGoogNow) {
return;
}
Preconditions.checkArgument(n.getType() == Token.NEW);
Node date = n.getFirstChild();
if (!NodeUtil.isName(date) || !"Date".equals(date.getString())) {
return;
}
Node callGoogNow = date.getNext();
if (callGoogNow == null || !NodeUtil.isCall(callGoogNow) ||
callGoogNow.getNext() != null) {
return;
}
Node googNow = callGoogNow.getFirstChild();
String googNowQName = googNow.getQualifiedName();
if (googNowQName == null || !"goog.now".equals(googNowQName)
|| googNow.getNext() != null) {
return;
}
n.removeChild(callGoogNow);
compiler.reportCodeChange();
}
/**
* Verifies that a provide method call has exactly one argument,
* and that it's a string literal and that the contents of the string are
* valid JS tokens. Reports a compile error if it doesn't.
*
* @return Whether the argument checked out okay
*/
private boolean verifyProvide(NodeTraversal t, Node methodName, Node arg) {
if (!verifyArgument(t, methodName, arg)) {
return false;
}
for (String part : arg.getString().split("\\.")) {
if (!NodeUtil.isValidPropertyName(part)) {
compiler.report(t.makeError(arg, INVALID_PROVIDE_ERROR, part));
return false;
}
Closure, 151
<FILEB>
<CHANGES>
@Option(name = "--version",
usage = "Prints the compiler version to stderr.")
private boolean version = false;
<CHANGEE>
<CHANGES>
private static final String configResource =
"com.google.javascript.jscomp.parsing.ParserConfig";
<CHANGEE>
<CHANGES>
}
if (flags.version) {
ResourceBundle config = ResourceBundle.getBundle(configResource);
err.println(
"Closure Compiler (http://code.google.com/p/closure/compiler)\n" +
"Version: " + config.getString("compiler.version") + "\n" +
"Built on: " + config.getString("compiler.date"));
err.flush();
<CHANGEE>
<FILEE>
<FILEB>
+ "goog.require(), goog.provide(), and goog.exportSymbol()")
private boolean process_closure_primitives = true;
@Option(name = "--manage_closure_dependencies",
handler = BooleanOptionHandler.class,
usage = "Automatically sort dependencies so that a file that "
+ "goog.provides symbol X will always come before a file that "
+ "goog.requires symbol X. If an input provides symbols, and "
+ "those symbols are never required, then that input will not "
+ "be included in the compilation.")
private boolean manage_closure_dependencies = false;
@Option(name = "--output_manifest",
usage = "Prints out a list of all the files in the compilation. "
+ "If --manage_closure_dependencies is on, this will not include "
+ "files that got dropped because they were not required. "
+ "The %outname% placeholder expands to the js output file. "
+ "If you're using modularization, using %outname% will create "
+ "a manifest for each module.")
private String output_manifest = "";
<CHANGES>
<CHANGEE>
// Our own option parser to be backwards-compatible.
// It needs to be public because of the crazy reflection that args4j does.
public static class BooleanOptionHandler extends OptionHandler<Boolean> {
private static final Set<String> TRUES =
Sets.newHashSet("true", "on", "yes", "1");
private static final Set<String> FALSES =
Sets.newHashSet("false", "off", "no", "0");
public BooleanOptionHandler(
CmdLineParser parser, OptionDef option,
Setter<? super Boolean> setter) {
super(parser, option, setter);
}
private static enum FormattingOption {
PRETTY_PRINT,
PRINT_INPUT_DELIMITER,
;
private void applyToOptions(CompilerOptions options) {
switch (this) {
case PRETTY_PRINT:
options.prettyPrint = true;
break;
case PRINT_INPUT_DELIMITER:
options.printInputDelimiter = true;
break;
default:
throw new RuntimeException("Unknown formatting option: " + this);
}
}
}
private final Flags flags = new Flags();
<CHANGES>
<CHANGEE>
private boolean is<SCANS> (a = b).c = null;
// We don't want to exploit the first assign. Similarly:
// a.b = null;
// a.b.c = null;
// We don't want to exploit the first assign either.
//
// To protect against this, we simply only inline when the left side
// is guaranteed to evaluate to the same L-value no matter what.
Node leftSide = next.getFirstChild();
if (leftSide.getType() == Token.NAME ||
leftSide.getType() == Token.GETPROP &&
leftSide.getFirstChild().getType() == Token.THIS) {
// Dive down the right side of the assign.
parent = next;
next = leftSide.getNext();
break;
} else {
return false;
}
default:
// Return without inlining a thing
return false;
}
}
return false;
}
}
/**
* Checks name referenced in node to determine if it might have
* changed.
* @return Whether the replacement can be made.
*/
private boolean isSafeReplacement(Node node, Node replacement) {
// No checks are needed for simple names.
if (node.getType() == Token.NAME) {
return true;
}
Preconditions.checkArgument(node.getType() == Token.GETPROP);
Node name = node.getFirstChild();
if (name.getType() == Token.NAME
&& isNameAssignedTo(name.getString(), replacement)) {
return false;
}
return true;
}
/**
* @return Whether name is assigned in the expression rooted at node.
*/
private boolean isNameAssignedTo(String name, Node node) {
for (Node c = node.getFirstChild(); c != null; c = c.getNext()) {
if (isNameAssignedTo(name, c)) {
return true;
}
}
if (node.getType() == Token.NAME) {
Node parent = node.getParent();
if (parent.getType() == Token.ASSIGN && parent.getFirstChild() == node) {
if (name.equals(node.getString())) {
return true;
}
}
}
return false;
}
/**
* Gathers all of the variable declarations that should be collapsed into one.